Skip to content

Commit 6a3b558

Browse files
committed
Auto merge of #32644 - oli-obk:check_all_constants_early, r=nrc
check constants even if they are not used in the current crate For now this is just a `warn`-by-default lint. I suggest to make it a `deny`-by-default lint in the next release cycle (so no dependencies break), and then in another release cycle move to an error. cc #19265 cc #3170
2 parents f92ce2e + 913a2b4 commit 6a3b558

8 files changed

+60
-18
lines changed

src/librustc_const_eval/eval.rs

+17-6
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,15 @@ pub fn eval_const_expr(tcx: &TyCtxt, e: &Expr) -> ConstVal {
343343
match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
344344
Ok(r) => r,
345345
// non-const path still needs to be a fatal error, because enums are funky
346-
Err(ref s) if s.kind == NonConstPath => tcx.sess.span_fatal(s.span, &s.description()),
347346
Err(s) => {
348-
tcx.sess.span_err(s.span, &s.description());
349-
Dummy
347+
match s.kind {
348+
NonConstPath |
349+
UnimplementedConstVal(_) => tcx.sess.span_fatal(s.span, &s.description()),
350+
_ => {
351+
tcx.sess.span_err(s.span, &s.description());
352+
Dummy
353+
}
354+
}
350355
},
351356
}
352357
}
@@ -607,6 +612,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
607612
const_val => signal!(e, NotOn(const_val)),
608613
}
609614
}
615+
hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
610616
hir::ExprBinary(op, ref a, ref b) => {
611617
let b_ty = match op.node {
612618
hir::BiShl | hir::BiShr => ty_hint.erase_hint(),
@@ -745,7 +751,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
745751
if let Some(const_expr) = lookup_variant_by_id(tcx, enum_def, variant_def) {
746752
eval_const_expr_partial(tcx, const_expr, ty_hint, None)?
747753
} else {
748-
signal!(e, NonConstPath);
754+
signal!(e, UnimplementedConstVal("enum variants"));
749755
}
750756
}
751757
Def::Struct(..) => {
@@ -768,6 +774,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
768774
let callee_val = eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)?;
769775
let did = match callee_val {
770776
Function(did) => did,
777+
Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
771778
callee => signal!(e, CallOn(callee)),
772779
};
773780
let (decl, result) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) {
@@ -798,7 +805,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
798805
hir::ExprBlock(ref block) => {
799806
match block.expr {
800807
Some(ref expr) => eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)?,
801-
None => bug!(),
808+
None => signal!(e, UnimplementedConstVal("empty block")),
802809
}
803810
}
804811
hir::ExprType(ref e, _) => eval_const_expr_partial(tcx, &e, ty_hint, fn_args)?,
@@ -840,7 +847,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
840847
},
841848

842849
Str(ref s) if idx as usize >= s.len() => signal!(e, IndexOutOfBounds),
843-
Str(_) => bug!("unimplemented"), // FIXME: return a const char
850+
// FIXME: return a const char
851+
Str(_) => signal!(e, UnimplementedConstVal("indexing into str")),
844852
_ => signal!(e, IndexedNonVec),
845853
}
846854
}
@@ -894,6 +902,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
894902
signal!(base, ExpectedConstStruct);
895903
}
896904
}
905+
hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")),
897906
_ => signal!(e, MiscCatchAll)
898907
};
899908

@@ -1073,6 +1082,7 @@ fn cast_const_int<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstInt, ty: ty::Ty) -> CastRe
10731082
Ok(Float(val as f64))
10741083
},
10751084
ty::TyFloat(ast::FloatTy::F32) => Ok(Float(val.to_u64().unwrap() as f32 as f64)),
1085+
ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
10761086
_ => Err(CannotCast),
10771087
}
10781088
}
@@ -1094,6 +1104,7 @@ fn cast_const<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult
10941104
Bool(b) => cast_const_int(tcx, Infer(b as u64), ty),
10951105
Float(f) => cast_const_float(tcx, f, ty),
10961106
Char(c) => cast_const_int(tcx, Infer(c as u64), ty),
1107+
Function(_) => Err(UnimplementedConstVal("casting fn pointers")),
10971108
_ => Err(CannotCast),
10981109
}
10991110
}

src/librustc_passes/consts.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ 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;
31+
use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal};
3232
use rustc_const_eval::EvalHint::ExprTypeChecked;
3333
use rustc::middle::def::Def;
3434
use rustc::middle::def_id::DefId;
@@ -110,6 +110,16 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
110110
entry.insert(ConstQualif::empty());
111111
}
112112
}
113+
if let Err(err) = eval_const_expr_partial(self.tcx, expr, ExprTypeChecked, None) {
114+
match err.kind {
115+
UnimplementedConstVal(_) => {},
116+
IndexOpFeatureGated => {},
117+
_ => self.tcx.sess.add_lint(CONST_ERR, expr.id, expr.span,
118+
format!("constant evaluation error: {}. This will \
119+
become a HARD ERROR in the future",
120+
err.description())),
121+
}
122+
}
113123
self.with_mode(mode, |this| {
114124
this.with_euv(None, |euv| euv.consume_expr(expr));
115125
this.visit_expr(expr);
@@ -435,6 +445,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
435445
match eval_const_expr_partial(
436446
self.tcx, ex, ExprTypeChecked, None) {
437447
Ok(_) => {}
448+
Err(ConstEvalErr { kind: UnimplementedConstVal(_), ..}) |
438449
Err(ConstEvalErr { kind: IndexOpFeatureGated, ..}) => {},
439450
Err(msg) => {
440451
self.tcx.sess.add_lint(CONST_ERR, ex.id,
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2016 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(const_indexing)]
12+
#![deny(const_err)]
13+
14+
pub const A: i8 = -std::i8::MIN; //~ ERROR attempted to negate with overflow
15+
pub const B: u8 = 200u8 + 200u8; //~ ERROR attempted to add with overflow
16+
pub const C: u8 = 200u8 * 4; //~ ERROR attempted to multiply with overflow
17+
pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR attempted to subtract with overflow
18+
pub const E: u8 = [5u8][1]; //~ ERROR index out of bounds
19+
20+
fn main() {
21+
let _e = [6u8][1];
22+
}

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

+2-5
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,11 @@
1010

1111
#![feature(rustc_attrs)]
1212
#![allow(exceeding_bitshifts)]
13-
#![deny(const_err)]
1413

1514
fn black_box<T>(_: T) {
1615
unimplemented!()
1716
}
1817

19-
const BLA: u8 = 200u8 + 200u8;
20-
//~^ ERROR attempted to add with overflow
21-
2218
#[rustc_no_mir] // FIXME #29769 MIR overflow checking is TBD.
2319
fn main() {
2420
let a = -std::i8::MIN;
@@ -30,7 +26,8 @@ fn main() {
3026
//~^ WARN attempted to multiply with overflow
3127
let d = 42u8 - (42u8 + 1);
3228
//~^ WARN attempted to subtract with overflow
33-
let _e = BLA;
29+
let _e = [5u8][1];
30+
//~^ ERROR const index-expr is out of bounds
3431
black_box(a);
3532
black_box(b);
3633
black_box(c);

src/test/compile-fail/const-eval-span.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
struct S(i32);
1515

1616
const CONSTANT: S = S(0);
17-
//~^ ERROR: constant evaluation error: call on struct [E0080]
17+
//~^ ERROR: unimplemented constant expression: tuple struct constructors [E0080]
1818

1919
enum E {
2020
V = CONSTANT,

src/test/compile-fail/const-pattern-not-const-evaluable.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ enum Cake {
1717
use Cake::*;
1818

1919
const BOO: (Cake, Cake) = (Marmor, BlackForest);
20-
//~^ ERROR: constant evaluation error: non-constant path in constant expression [E0471]
20+
//~^ ERROR: constant evaluation error: unimplemented constant expression: enum variants [E0471]
2121
const FOO: Cake = BOO.1;
2222

2323
const fn foo() -> Cake {
24-
Marmor //~ ERROR: constant evaluation error: non-constant path in constant expression [E0471]
25-
//~^ ERROR: non-constant path in constant expression
24+
Marmor //~ ERROR: constant evaluation error: unimplemented constant expression: enum variants
25+
//~^ ERROR: unimplemented constant expression: enum variants
2626
}
2727

2828
const WORKS: Cake = Marmor;

src/test/compile-fail/feature-gate-negate-unsigned.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ impl std::ops::Neg for S {
1717
}
1818

1919
const _MAX: usize = -1;
20-
//~^ ERROR unary negation of unsigned integer
20+
//~^ WARN unary negation of unsigned integer
21+
//~| ERROR unary negation of unsigned integer
2122
//~| HELP use a cast or the `!` operator
2223

2324
fn main() {

src/test/compile-fail/non-constant-enum-for-vec-repeat.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ enum State { ST_NULL, ST_WHITESPACE }
1515

1616
fn main() {
1717
[State::ST_NULL; (State::ST_WHITESPACE as usize)];
18-
//~^ ERROR expected constant integer for repeat count, but non-constant path
18+
//~^ ERROR expected constant integer for repeat count, but unimplemented constant expression
1919
}

0 commit comments

Comments
 (0)