Skip to content

Commit b52d76a

Browse files
committed
Auto merge of #33214 - oli-obk:const_err_var_exprs, r=eddyb
report `const_err` on all expressions that can fail also a drive-by fix for reporting an "overflow in shift *left*" when shifting an `i64` *right* This increases the warning noise for shifting by more than the bitwidth and for `-T::MIN`. I can silence the bitwidth warnings explicitly and fix the const evaluator to make sure `--$expr` is treated exactly like `$expr` (which is kinda wrong, but mathematically right). r? @eddyb
2 parents 80bff1e + 5cdcad9 commit b52d76a

File tree

11 files changed

+116
-67
lines changed

11 files changed

+116
-67
lines changed

src/librustc_const_eval/eval.rs

+45-38
Original file line numberDiff line numberDiff line change
@@ -562,44 +562,51 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
562562
let result = match e.node {
563563
hir::ExprUnary(hir::UnNeg, ref inner) => {
564564
// unary neg literals already got their sign during creation
565-
if let hir::ExprLit(ref lit) = inner.node {
566-
use syntax::ast::*;
567-
use syntax::ast::LitIntType::*;
568-
const I8_OVERFLOW: u64 = ::std::i8::MAX as u64 + 1;
569-
const I16_OVERFLOW: u64 = ::std::i16::MAX as u64 + 1;
570-
const I32_OVERFLOW: u64 = ::std::i32::MAX as u64 + 1;
571-
const I64_OVERFLOW: u64 = ::std::i64::MAX as u64 + 1;
572-
match (&lit.node, ety.map(|t| &t.sty)) {
573-
(&LitKind::Int(I8_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I8))) |
574-
(&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
575-
return Ok(Integral(I8(::std::i8::MIN)))
576-
},
577-
(&LitKind::Int(I16_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I16))) |
578-
(&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
579-
return Ok(Integral(I16(::std::i16::MIN)))
580-
},
581-
(&LitKind::Int(I32_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I32))) |
582-
(&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
583-
return Ok(Integral(I32(::std::i32::MIN)))
584-
},
585-
(&LitKind::Int(I64_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I64))) |
586-
(&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
587-
return Ok(Integral(I64(::std::i64::MIN)))
588-
},
589-
(&LitKind::Int(n, Unsuffixed), Some(&ty::TyInt(IntTy::Is))) |
590-
(&LitKind::Int(n, Signed(IntTy::Is)), _) => {
591-
match tcx.sess.target.int_type {
592-
IntTy::I32 => if n == I32_OVERFLOW {
593-
return Ok(Integral(Isize(Is32(::std::i32::MIN))));
594-
},
595-
IntTy::I64 => if n == I64_OVERFLOW {
596-
return Ok(Integral(Isize(Is64(::std::i64::MIN))));
597-
},
598-
_ => bug!(),
599-
}
600-
},
601-
_ => {},
602-
}
565+
match inner.node {
566+
hir::ExprLit(ref lit) => {
567+
use syntax::ast::*;
568+
use syntax::ast::LitIntType::*;
569+
const I8_OVERFLOW: u64 = ::std::i8::MAX as u64 + 1;
570+
const I16_OVERFLOW: u64 = ::std::i16::MAX as u64 + 1;
571+
const I32_OVERFLOW: u64 = ::std::i32::MAX as u64 + 1;
572+
const I64_OVERFLOW: u64 = ::std::i64::MAX as u64 + 1;
573+
match (&lit.node, ety.map(|t| &t.sty)) {
574+
(&LitKind::Int(I8_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I8))) |
575+
(&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
576+
return Ok(Integral(I8(::std::i8::MIN)))
577+
},
578+
(&LitKind::Int(I16_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I16))) |
579+
(&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
580+
return Ok(Integral(I16(::std::i16::MIN)))
581+
},
582+
(&LitKind::Int(I32_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I32))) |
583+
(&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
584+
return Ok(Integral(I32(::std::i32::MIN)))
585+
},
586+
(&LitKind::Int(I64_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I64))) |
587+
(&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
588+
return Ok(Integral(I64(::std::i64::MIN)))
589+
},
590+
(&LitKind::Int(n, Unsuffixed), Some(&ty::TyInt(IntTy::Is))) |
591+
(&LitKind::Int(n, Signed(IntTy::Is)), _) => {
592+
match tcx.sess.target.int_type {
593+
IntTy::I32 => if n == I32_OVERFLOW {
594+
return Ok(Integral(Isize(Is32(::std::i32::MIN))));
595+
},
596+
IntTy::I64 => if n == I64_OVERFLOW {
597+
return Ok(Integral(Isize(Is64(::std::i64::MIN))));
598+
},
599+
_ => bug!(),
600+
}
601+
},
602+
_ => {},
603+
}
604+
},
605+
hir::ExprUnary(hir::UnNeg, ref inner) => {
606+
// skip `--$expr`
607+
return eval_const_expr_partial(tcx, inner, ty_hint, fn_args);
608+
},
609+
_ => {},
603610
}
604611
match eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)? {
605612
Float(f) => Float(-f),

src/librustc_const_math/int.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ impl ::std::ops::Shr<ConstInt> for ConstInt {
503503
I8(a) => Ok(I8(overflowing!(a.overflowing_shr(b), Op::Shr))),
504504
I16(a) => Ok(I16(overflowing!(a.overflowing_shr(b), Op::Shr))),
505505
I32(a) => Ok(I32(overflowing!(a.overflowing_shr(b), Op::Shr))),
506-
I64(a) => Ok(I64(overflowing!(a.overflowing_shr(b), Op::Shl))),
506+
I64(a) => Ok(I64(overflowing!(a.overflowing_shr(b), Op::Shr))),
507507
Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
508508
Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
509509
U8(a) => Ok(U8(overflowing!(a.overflowing_shr(b), Op::Shr))),

src/librustc_const_math/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,4 @@ mod err;
4040
pub use int::*;
4141
pub use us::*;
4242
pub use is::*;
43-
pub use err::ConstMathErr;
43+
pub use err::{ConstMathErr, Op};

src/librustc_passes/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ crate-type = ["dylib"]
1212
log = { path = "../liblog" }
1313
rustc = { path = "../librustc" }
1414
rustc_const_eval = { path = "../librustc_const_eval" }
15+
rustc_const_math = { path = "../librustc_const_math" }
1516
syntax = { path = "../libsyntax" }

src/librustc_passes/consts.rs

+25-25
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ use rustc::dep_graph::DepNode;
2828
use rustc::ty::cast::{CastKind};
2929
use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs};
3030
use rustc_const_eval::{eval_const_expr_partial, lookup_const_by_id};
31-
use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal};
32-
use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
31+
use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
32+
use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
33+
use rustc_const_eval::ErrKind::UnresolvedPath;
3334
use rustc_const_eval::EvalHint::ExprTypeChecked;
35+
use rustc_const_math::{ConstMathErr, Op};
3436
use rustc::hir::def::Def;
3537
use rustc::hir::def_id::DefId;
3638
use rustc::middle::expr_use_visitor as euv;
@@ -437,29 +439,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
437439
}
438440
intravisit::walk_expr(self, ex);
439441
}
440-
// Division by zero and overflow checking.
441-
hir::ExprBinary(op, _, _) => {
442-
intravisit::walk_expr(self, ex);
443-
let div_or_rem = op.node == hir::BiDiv || op.node == hir::BiRem;
444-
match node_ty.sty {
445-
ty::TyUint(_) | ty::TyInt(_) if div_or_rem => {
446-
if !self.qualif.intersects(ConstQualif::NOT_CONST) {
447-
match eval_const_expr_partial(
448-
self.tcx, ex, ExprTypeChecked, None) {
449-
Ok(_) => {}
450-
Err(ConstEvalErr { kind: UnimplementedConstVal(_), ..}) |
451-
Err(ConstEvalErr { kind: IndexOpFeatureGated, ..}) => {},
452-
Err(msg) => {
453-
self.tcx.sess.add_lint(CONST_ERR, ex.id,
454-
msg.span,
455-
msg.description().into_owned())
456-
}
457-
}
458-
}
459-
}
460-
_ => {}
461-
}
462-
}
463442
_ => intravisit::walk_expr(self, ex)
464443
}
465444

@@ -505,6 +484,27 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
505484
}
506485
None => {}
507486
}
487+
488+
if self.mode == Mode::Var && !self.qualif.intersects(ConstQualif::NOT_CONST) {
489+
match eval_const_expr_partial(self.tcx, ex, ExprTypeChecked, None) {
490+
Ok(_) => {}
491+
Err(ConstEvalErr { kind: UnimplementedConstVal(_), ..}) |
492+
Err(ConstEvalErr { kind: MiscCatchAll, ..}) |
493+
Err(ConstEvalErr { kind: MiscBinaryOp, ..}) |
494+
Err(ConstEvalErr { kind: NonConstPath, ..}) |
495+
Err(ConstEvalErr { kind: UnresolvedPath, ..}) |
496+
Err(ConstEvalErr { kind: ErroneousReferencedConstant(_), ..}) |
497+
Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), ..}) |
498+
Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), ..}) |
499+
Err(ConstEvalErr { kind: IndexOpFeatureGated, ..}) => {},
500+
Err(msg) => {
501+
self.tcx.sess.add_lint(CONST_ERR, ex.id,
502+
msg.span,
503+
msg.description().into_owned())
504+
}
505+
}
506+
}
507+
508508
self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
509509
// Don't propagate certain flags.
510510
self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);

src/librustc_passes/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
extern crate core;
3131
#[macro_use] extern crate rustc;
3232
extern crate rustc_const_eval;
33+
extern crate rustc_const_math;
3334

3435
#[macro_use] extern crate log;
3536
#[macro_use] extern crate syntax;

src/test/compile-fail/const-err-early.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@ pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR attempted to subtract with overfl
1818
pub const E: u8 = [5u8][1]; //~ ERROR index out of bounds
1919

2020
fn main() {
21-
let _e = [6u8][1];
21+
let _e = [6u8][1]; //~ ERROR: array index out of bounds
2222
}

src/test/compile-fail/const-err.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// these errors are not actually "const_err", they occur in trans/consts
12+
// and are unconditional warnings that can't be denied or allowed
13+
1114
#![feature(rustc_attrs)]
1215
#![allow(exceeding_bitshifts)]
16+
#![allow(const_err)]
1317

1418
fn black_box<T>(_: T) {
1519
unimplemented!()
@@ -21,7 +25,7 @@ fn main() {
2125
//~^ WARN attempted to negate with overflow
2226
let b = 200u8 + 200u8 + 200u8;
2327
//~^ WARN attempted to add with overflow
24-
//~^^ WARN attempted to add with overflow
28+
//~| WARN attempted to add with overflow
2529
let c = 200u8 * 4;
2630
//~^ WARN attempted to multiply with overflow
2731
let d = 42u8 - (42u8 + 1);

src/test/compile-fail/const-err2.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2012 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+
11+
#![feature(rustc_attrs)]
12+
#![allow(exceeding_bitshifts)]
13+
#![deny(const_err)]
14+
15+
fn black_box<T>(_: T) {
16+
unimplemented!()
17+
}
18+
19+
fn main() {
20+
let a = -std::i8::MIN;
21+
//~^ ERROR attempted to negate with overflow
22+
let b = 200u8 + 200u8 + 200u8;
23+
//~^ ERROR attempted to add with overflow
24+
//~| ERROR attempted to add with overflow
25+
let c = 200u8 * 4;
26+
//~^ ERROR attempted to multiply with overflow
27+
let d = 42u8 - (42u8 + 1);
28+
//~^ ERROR attempted to subtract with overflow
29+
let _e = [5u8][1];
30+
black_box(a);
31+
black_box(b);
32+
black_box(c);
33+
black_box(d);
34+
}

src/test/compile-fail/lint-exceeding-bitshifts.rs

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ fn main() {
5353
let n = n << 8; //~ ERROR: bitshift exceeds the type's number of bits
5454

5555
let n = 1u8 << -8; //~ ERROR: bitshift exceeds the type's number of bits
56+
//~^ WARN: attempted to shift by a negative amount
5657

5758
let n = 1u8 << (4+3);
5859
let n = 1u8 << (4+4); //~ ERROR: bitshift exceeds the type's number of bits

src/test/compile-fail/lint-type-overflow2.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111

1212
#![deny(overflowing_literals)]
13+
#![deny(const_err)]
1314

1415
#[allow(unused_variables)]
1516
fn main() {

0 commit comments

Comments
 (0)