Skip to content

Commit e97f104

Browse files
committed
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
1 parent e57f061 commit e97f104

File tree

3 files changed

+31
-14
lines changed

3 files changed

+31
-14
lines changed

src/librustc_const_eval/eval.rs

+16-13
Original file line numberDiff line numberDiff line change
@@ -464,33 +464,36 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
464464
if let hir::ExprLit(ref lit) = inner.node {
465465
use syntax::ast::*;
466466
use syntax::ast::LitIntType::*;
467-
const I8_OVERFLOW: u128 = i8::max_value() as u128 + 1;
468-
const I16_OVERFLOW: u128 = i16::max_value() as u128 + 1;
469-
const I32_OVERFLOW: u128 = i32::max_value() as u128 + 1;
470-
const I64_OVERFLOW: u128 = i64::max_value() as u128 + 1;
471-
const I128_OVERFLOW: u128 = i128::max_value() as u128 + 1;
467+
const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128;
468+
const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128;
469+
const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
470+
const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
471+
const I128_OVERFLOW: u128 = i128::min_value() as u128;
472472
match (&lit.node, ety.map(|t| &t.sty)) {
473-
(&LitKind::Int(I8_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I8))) |
473+
(&LitKind::Int(I8_OVERFLOW, _), Some(&ty::TyInt(IntTy::I8))) |
474474
(&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
475475
return Ok(Integral(I8(i8::min_value())))
476476
},
477-
(&LitKind::Int(I16_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I16))) |
477+
(&LitKind::Int(I16_OVERFLOW, _), Some(&ty::TyInt(IntTy::I16))) |
478478
(&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
479479
return Ok(Integral(I16(i16::min_value())))
480480
},
481-
(&LitKind::Int(I32_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I32))) |
481+
(&LitKind::Int(I32_OVERFLOW, _), Some(&ty::TyInt(IntTy::I32))) |
482482
(&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
483483
return Ok(Integral(I32(i32::min_value())))
484484
},
485-
(&LitKind::Int(I64_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I64))) |
485+
(&LitKind::Int(I64_OVERFLOW, _), Some(&ty::TyInt(IntTy::I64))) |
486486
(&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
487487
return Ok(Integral(I64(i64::min_value())))
488488
},
489-
(&LitKind::Int(I128_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I128))) |
490-
(&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
491-
return Ok(Integral(I128(i128::min_value())))
489+
(&LitKind::Int(n, _), Some(&ty::TyInt(IntTy::I128))) |
490+
(&LitKind::Int(n, Signed(IntTy::I128)), _) => {
491+
// SNAP: replace n in pattern with I128_OVERFLOW and remove this if.
492+
if n == I128_OVERFLOW {
493+
return Ok(Integral(I128(i128::min_value())))
494+
}
492495
},
493-
(&LitKind::Int(n, Unsuffixed), Some(&ty::TyInt(IntTy::Is))) |
496+
(&LitKind::Int(n, _), Some(&ty::TyInt(IntTy::Is))) |
494497
(&LitKind::Int(n, Signed(IntTy::Is)), _) => {
495498
match tcx.sess.target.int_type {
496499
IntTy::I16 => if n == I16_OVERFLOW {

src/librustc_const_math/int.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ impl ::std::ops::Neg for ConstInt {
661661
a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) |
662662
a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a),
663663
U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation),
664-
Infer(a @ 0...ubounds::I64MAX) => Ok(InferSigned(-(a as i128))),
664+
Infer(a @ 0...ubounds::I128MAX) => Ok(InferSigned(-(a as i128))),
665665
Infer(_) => Err(Overflow(Op::Neg)),
666666
InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))),
667667
}

src/test/run-pass/issue-38987.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
#![feature(i128_type)]
11+
12+
fn main() {
13+
let _ = -0x8000_0000_0000_0000_0000_0000_0000_0000i128;
14+
}

0 commit comments

Comments
 (0)