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:
commit
3f2ad610a8
23 changed files with 376 additions and 194 deletions
36
src/test/compile-fail/const-err.rs
Normal file
36
src/test/compile-fail/const-err.rs
Normal 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);
|
||||
}
|
||||
|
|
@ -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)]
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue