about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorSimonas Kazlauskas <git@kazlauskas.me>2017-01-11 16:28:23 +0200
committerSimonas Kazlauskas <git@kazlauskas.me>2017-01-11 19:38:44 +0200
commite97f104da64d047c919fc2fccf720efd46f30261 (patch)
tree01852a2075f40887626b9ff2c4d2967bf257491c /src
parente57f061be20666eb0506f6f41551c798bbb38b60 (diff)
downloadrust-e97f104da64d047c919fc2fccf720efd46f30261.tar.gz
rust-e97f104da64d047c919fc2fccf720efd46f30261.zip
Fix two const-eval issues related to i128 negation
First issue here was the fact that we’d only allow negating integers in i64 range in case the
integer was not infered yes. While this is not the direct cause of the issue, its still good to fix
it.

The real issue here is the code handling specifically the `min_value` literals. While I128_OVERFLOW
has the expected value (0x8000_..._0000), match using this value as a pattern is handled
incorrectly by the stage1 compiler (it seems to be handled correctly, by the stage2 compiler). So
what we do here is extract this pattern into an explicit `==` until the next snapshot.

Fixes #38987
Diffstat (limited to 'src')
-rw-r--r--src/librustc_const_eval/eval.rs29
-rw-r--r--src/librustc_const_math/int.rs2
-rw-r--r--src/test/run-pass/issue-38987.rs14
3 files changed, 31 insertions, 14 deletions
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index bc72c8fb9b6..c899d2109f5 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -464,33 +464,36 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         if let hir::ExprLit(ref lit) = inner.node {
             use syntax::ast::*;
             use syntax::ast::LitIntType::*;
-            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;
+            const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128;
+            const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128;
+            const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
+            const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
+            const I128_OVERFLOW: u128 = i128::min_value() as u128;
             match (&lit.node, ety.map(|t| &t.sty)) {
-                (&LitKind::Int(I8_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I8))) |
+                (&LitKind::Int(I8_OVERFLOW, _), Some(&ty::TyInt(IntTy::I8))) |
                 (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
                     return Ok(Integral(I8(i8::min_value())))
                 },
-                (&LitKind::Int(I16_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I16))) |
+                (&LitKind::Int(I16_OVERFLOW, _), Some(&ty::TyInt(IntTy::I16))) |
                 (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
                     return Ok(Integral(I16(i16::min_value())))
                 },
-                (&LitKind::Int(I32_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I32))) |
+                (&LitKind::Int(I32_OVERFLOW, _), Some(&ty::TyInt(IntTy::I32))) |
                 (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
                     return Ok(Integral(I32(i32::min_value())))
                 },
-                (&LitKind::Int(I64_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I64))) |
+                (&LitKind::Int(I64_OVERFLOW, _), Some(&ty::TyInt(IntTy::I64))) |
                 (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
                     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, _), Some(&ty::TyInt(IntTy::I128))) |
+                (&LitKind::Int(n, Signed(IntTy::I128)), _) => {
+                    // SNAP: replace n in pattern with I128_OVERFLOW and remove this if.
+                    if n == I128_OVERFLOW {
+                        return Ok(Integral(I128(i128::min_value())))
+                    }
                 },
-                (&LitKind::Int(n, Unsuffixed), Some(&ty::TyInt(IntTy::Is))) |
+                (&LitKind::Int(n, _), Some(&ty::TyInt(IntTy::Is))) |
                 (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
                     match tcx.sess.target.int_type {
                         IntTy::I16 => if n == I16_OVERFLOW {
diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs
index 59eb4b70aa8..53f185b661b 100644
--- a/src/librustc_const_math/int.rs
+++ b/src/librustc_const_math/int.rs
@@ -661,7 +661,7 @@ impl ::std::ops::Neg for ConstInt {
             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(a @ 0...ubounds::I128MAX) => Ok(InferSigned(-(a as i128))),
             Infer(_) => Err(Overflow(Op::Neg)),
             InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))),
         }
diff --git a/src/test/run-pass/issue-38987.rs b/src/test/run-pass/issue-38987.rs
new file mode 100644
index 00000000000..a513476d4a3
--- /dev/null
+++ b/src/test/run-pass/issue-38987.rs
@@ -0,0 +1,14 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![feature(i128_type)]
+
+fn main() {
+    let _ = -0x8000_0000_0000_0000_0000_0000_0000_0000i128;
+}