Auto merge of #28845 - oli-obk:rfc1229, r=pnkfelix

This PR turns statically known erroneous code (e.g. numeric overflow) into a warning and continues normal code-generation to emit the same code that would have been generated without `check_const` detecting that the result can be computed at compile-time.

<del>It's not done yet, as I don't know how to properly emit a lint from trans. I can't seem to extract the real lint level of the item the erroneous expression is in.</del> It's an unconditional warning now.

r? @pnkfelix 

cc @nikomatsakis 

* [RFC 1229 text](https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md)
* RFC PR: rust-lang/rfcs#1229
* tracking issue: https://github.com/rust-lang/rust/issues/28238
This commit is contained in:
bors 2015-10-18 11:09:03 +00:00
commit 3f2ad610a8
23 changed files with 376 additions and 194 deletions

View file

@ -0,0 +1,36 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[allow(exceeding_bitshifts)]
#[deny(const_err)]
fn black_box<T>(_: T) {
unimplemented!()
}
const BLA: u8 = 200u8 + 200u8;
//~^ ERROR attempted to add with overflow
fn main() {
let a = -std::i8::MIN;
//~^ WARN attempted to negate with overflow
let b = 200u8 + 200u8 + 200u8;
//~^ WARN attempted to add with overflow
//~^^ WARN attempted to add with overflow
let c = 200u8 * 4;
//~^ WARN attempted to mul with overflow
let d = 42u8 - (42u8 + 1);
//~^ WARN attempted to sub with overflow
let _e = BLA;
black_box(a);
black_box(b);
black_box(c);
black_box(d);
}

View file

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(negate_unsigned)]
#![allow(unused_imports)]
#![feature(negate_unsigned)]

View file

@ -8,48 +8,50 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![deny(const_err)]
use std::{isize, i8, i16, i32, i64};
use std::thread;
fn main() {
assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
//~^ ERROR attempted to divide with overflow in a constant expression
//~^ ERROR attempted to divide with overflow
assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
//~^ ERROR attempted to divide with overflow in a constant expression
//~^ ERROR attempted to divide with overflow
assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
//~^ ERROR attempted to divide with overflow in a constant expression
//~^ ERROR attempted to divide with overflow
assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
//~^ ERROR attempted to divide with overflow in a constant expression
//~^ ERROR attempted to divide with overflow
assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
//~^ ERROR attempted to divide with overflow in a constant expression
//~^ ERROR attempted to divide with overflow
assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
//~^ ERROR attempted to divide by zero in a constant expression
//~^ ERROR attempted to divide by zero
assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
//~^ ERROR attempted to divide by zero in a constant expression
//~^ ERROR attempted to divide by zero
assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
//~^ ERROR attempted to divide by zero in a constant expression
//~^ ERROR attempted to divide by zero
assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
//~^ ERROR attempted to divide by zero in a constant expression
//~^ ERROR attempted to divide by zero
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
//~^ ERROR attempted to divide by zero in a constant expression
//~^ ERROR attempted to divide by zero
assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
//~^ ERROR attempted remainder with overflow in a constant expression
//~^ ERROR attempted remainder with overflow
assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
//~^ ERROR attempted remainder with overflow in a constant expression
//~^ ERROR attempted remainder with overflow
assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
//~^ ERROR attempted remainder with overflow in a constant expression
//~^ ERROR attempted remainder with overflow
assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
//~^ ERROR attempted remainder with overflow in a constant expression
//~^ ERROR attempted remainder with overflow
assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
//~^ ERROR attempted remainder with overflow in a constant expression
//~^ ERROR attempted remainder with overflow
assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
//~^ ERROR attempted remainder with a divisor of zero in a constant expression
//~^ ERROR attempted remainder with a divisor of zero
assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
//~^ ERROR attempted remainder with a divisor of zero in a constant expression
//~^ ERROR attempted remainder with a divisor of zero
assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
//~^ ERROR attempted remainder with a divisor of zero in a constant expression
//~^ ERROR attempted remainder with a divisor of zero
assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
//~^ ERROR attempted remainder with a divisor of zero in a constant expression
//~^ ERROR attempted remainder with a divisor of zero
assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
//~^ ERROR attempted remainder with a divisor of zero in a constant expression
//~^ ERROR attempted remainder with a divisor of zero
}

View file

@ -11,9 +11,7 @@
// error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
// compile-flags: -C debug-assertions
// (Work around constant-evaluation)
fn value() -> u8 { 200 }
fn main() {
let _x = value() + value() + value();
let _x = 200u8 + 200u8 + 200u8;
}

View file

@ -11,9 +11,8 @@
// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
// compile-flags: -C debug-assertions
// (Work around constant-evaluation)
fn id<T>(x: T) -> T { x }
#![warn(exceeding_bitshifts)]
fn main() {
let _x = 1_i32 << id(32);
let _x = 1_i32 << 32;
}

View file

@ -11,9 +11,8 @@
// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
// compile-flags: -C debug-assertions
// (Work around constant-evaluation)
fn id<T>(x: T) -> T { x }
#![warn(exceeding_bitshifts)]
fn main() {
let _x = 1 << id(-1);
let _x = 1 << -1;
}

View file

@ -11,9 +11,8 @@
// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
// compile-flags: -C debug-assertions
// (Work around constant-evaluation)
fn id<T>(x: T) -> T { x }
#![warn(exceeding_bitshifts)]
fn main() {
let _x = 1_u64 << id(64);
let _x = 1_u64 << 64;
}

View file

@ -14,12 +14,11 @@
// This function is checking that our automatic truncation does not
// sidestep the overflow checking.
// (Work around constant-evaluation)
fn id<T>(x: T) -> T { x }
#![warn(exceeding_bitshifts)]
fn main() {
// this signals overflow when checking is on
let x = 1_i8 << id(17);
let x = 1_i8 << 17;
// ... but when checking is off, the fallback will truncate the
// input to its lower three bits (= 1). Note that this is *not*

View file

@ -11,9 +11,6 @@
// error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
// compile-flags: -C debug-assertions
// (Work around constant-evaluation)
fn value() -> u8 { 200 }
fn main() {
let x = value() * 4;
let x = 200u8 * 4;
}

View file

@ -11,9 +11,6 @@
// error-pattern:thread '<main>' panicked at 'attempted to negate with overflow'
// compile-flags: -C debug-assertions
// (Work around constant-evaluation)
fn value() -> i8 { std::i8::MIN }
fn main() {
let _x = -value();
let _x = -std::i8::MIN;
}

View file

@ -11,9 +11,8 @@
// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
// compile-flags: -C debug-assertions
// (Work around constant-evaluation)
fn id<T>(x: T) -> T { x }
#![warn(exceeding_bitshifts)]
fn main() {
let _x = -1_i32 >> id(32);
let _x = -1_i32 >> 32;
}

View file

@ -11,9 +11,8 @@
// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
// compile-flags: -C debug-assertions
// (Work around constant-evaluation)
fn id<T>(x: T) -> T { x }
#![warn(exceeding_bitshifts)]
fn main() {
let _x = -1_i32 >> id(-1);
let _x = -1_i32 >> -1;
}

View file

@ -11,9 +11,8 @@
// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
// compile-flags: -C debug-assertions
// (Work around constant-evaluation)
fn id<T>(x: T) -> T { x }
#![warn(exceeding_bitshifts)]
fn main() {
let _x = -1_i64 >> id(64);
let _x = -1_i64 >> 64;
}

View file

@ -14,12 +14,11 @@
// This function is checking that our (type-based) automatic
// truncation does not sidestep the overflow checking.
// (Work around constant-evaluation)
fn id<T>(x: T) -> T { x }
#![warn(exceeding_bitshifts)]
fn main() {
// this signals overflow when checking is on
let x = 2_i8 >> id(17);
let x = 2_i8 >> 17;
// ... but when checking is off, the fallback will truncate the
// input to its lower three bits (= 1). Note that this is *not*

View file

@ -11,9 +11,6 @@
// error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
// compile-flags: -C debug-assertions
// (Work around constant-evaluation)
fn value() -> u8 { 42 }
fn main() {
let _x = value() - (value() + 1);
let _x = 42u8 - (42u8 + 1);
}

View file

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(num_wrapping)]
// Test inherent wrapping_* methods for {i,u}{size,8,16,32,64}.
use std::{i8, i16, i32, i64, isize};