From 913a2b4b0525c75ecf915076c4fd1e16187f8b51 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 1 Apr 2016 09:19:29 +0200 Subject: [PATCH] check constants even if they are unused in the current crate --- src/librustc_const_eval/eval.rs | 23 ++++++++++++++----- src/librustc_passes/consts.rs | 13 ++++++++++- src/test/compile-fail/const-err-early.rs | 22 ++++++++++++++++++ src/test/compile-fail/const-err.rs | 7 ++---- src/test/compile-fail/const-eval-span.rs | 2 +- .../const-pattern-not-const-evaluable.rs | 6 ++--- .../feature-gate-negate-unsigned.rs | 3 ++- .../non-constant-enum-for-vec-repeat.rs | 2 +- 8 files changed, 60 insertions(+), 18 deletions(-) create mode 100644 src/test/compile-fail/const-err-early.rs diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 4790e481937..5a00b4573de 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -343,10 +343,15 @@ pub fn eval_const_expr(tcx: &TyCtxt, e: &Expr) -> ConstVal { match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) { Ok(r) => r, // non-const path still needs to be a fatal error, because enums are funky - Err(ref s) if s.kind == NonConstPath => tcx.sess.span_fatal(s.span, &s.description()), Err(s) => { - tcx.sess.span_err(s.span, &s.description()); - Dummy + match s.kind { + NonConstPath | + UnimplementedConstVal(_) => tcx.sess.span_fatal(s.span, &s.description()), + _ => { + tcx.sess.span_err(s.span, &s.description()); + Dummy + } + } }, } } @@ -607,6 +612,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>, const_val => signal!(e, NotOn(const_val)), } } + hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")), hir::ExprBinary(op, ref a, ref b) => { let b_ty = match op.node { hir::BiShl | hir::BiShr => ty_hint.erase_hint(), @@ -745,7 +751,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>, if let Some(const_expr) = lookup_variant_by_id(tcx, enum_def, variant_def) { eval_const_expr_partial(tcx, const_expr, ty_hint, None)? } else { - signal!(e, NonConstPath); + signal!(e, UnimplementedConstVal("enum variants")); } } Def::Struct(..) => { @@ -768,6 +774,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>, let callee_val = eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)?; let did = match callee_val { Function(did) => did, + Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")), callee => signal!(e, CallOn(callee)), }; 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>, hir::ExprBlock(ref block) => { match block.expr { Some(ref expr) => eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)?, - None => bug!(), + None => signal!(e, UnimplementedConstVal("empty block")), } } 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>, }, Str(ref s) if idx as usize >= s.len() => signal!(e, IndexOutOfBounds), - Str(_) => bug!("unimplemented"), // FIXME: return a const char + // FIXME: return a const char + Str(_) => signal!(e, UnimplementedConstVal("indexing into str")), _ => signal!(e, IndexedNonVec), } } @@ -894,6 +902,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>, signal!(base, ExpectedConstStruct); } } + hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")), _ => signal!(e, MiscCatchAll) }; @@ -1073,6 +1082,7 @@ fn cast_const_int<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstInt, ty: ty::Ty) -> CastRe Ok(Float(val as f64)) }, ty::TyFloat(ast::FloatTy::F32) => Ok(Float(val.to_u64().unwrap() as f32 as f64)), + ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")), _ => Err(CannotCast), } } @@ -1094,6 +1104,7 @@ fn cast_const<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult Bool(b) => cast_const_int(tcx, Infer(b as u64), ty), Float(f) => cast_const_float(tcx, f, ty), Char(c) => cast_const_int(tcx, Infer(c as u64), ty), + Function(_) => Err(UnimplementedConstVal("casting fn pointers")), _ => Err(CannotCast), } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index a7f00888735..ba5d8ef45b6 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -28,7 +28,7 @@ use rustc::dep_graph::DepNode; use rustc::ty::cast::{CastKind}; use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs}; use rustc_const_eval::{eval_const_expr_partial, lookup_const_by_id}; -use rustc_const_eval::ErrKind::IndexOpFeatureGated; +use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal}; use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc::middle::def::Def; use rustc::middle::def_id::DefId; @@ -110,6 +110,16 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { entry.insert(ConstQualif::empty()); } } + if let Err(err) = eval_const_expr_partial(self.tcx, expr, ExprTypeChecked, None) { + match err.kind { + UnimplementedConstVal(_) => {}, + IndexOpFeatureGated => {}, + _ => self.tcx.sess.add_lint(CONST_ERR, expr.id, expr.span, + format!("constant evaluation error: {}. This will \ + become a HARD ERROR in the future", + err.description())), + } + } self.with_mode(mode, |this| { this.with_euv(None, |euv| euv.consume_expr(expr)); this.visit_expr(expr); @@ -435,6 +445,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { match eval_const_expr_partial( self.tcx, ex, ExprTypeChecked, None) { Ok(_) => {} + Err(ConstEvalErr { kind: UnimplementedConstVal(_), ..}) | Err(ConstEvalErr { kind: IndexOpFeatureGated, ..}) => {}, Err(msg) => { self.tcx.sess.add_lint(CONST_ERR, ex.id, diff --git a/src/test/compile-fail/const-err-early.rs b/src/test/compile-fail/const-err-early.rs new file mode 100644 index 00000000000..cdcdb919bde --- /dev/null +++ b/src/test/compile-fail/const-err-early.rs @@ -0,0 +1,22 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(const_indexing)] +#![deny(const_err)] + +pub const A: i8 = -std::i8::MIN; //~ ERROR attempted to negate with overflow +pub const B: u8 = 200u8 + 200u8; //~ ERROR attempted to add with overflow +pub const C: u8 = 200u8 * 4; //~ ERROR attempted to multiply with overflow +pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR attempted to subtract with overflow +pub const E: u8 = [5u8][1]; //~ ERROR index out of bounds + +fn main() { + let _e = [6u8][1]; +} diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs index 882e4cb2d47..45e8fc37d87 100644 --- a/src/test/compile-fail/const-err.rs +++ b/src/test/compile-fail/const-err.rs @@ -10,15 +10,11 @@ #![feature(rustc_attrs)] #![allow(exceeding_bitshifts)] -#![deny(const_err)] fn black_box(_: T) { unimplemented!() } -const BLA: u8 = 200u8 + 200u8; -//~^ ERROR attempted to add with overflow - #[rustc_no_mir] // FIXME #29769 MIR overflow checking is TBD. fn main() { let a = -std::i8::MIN; @@ -30,7 +26,8 @@ fn main() { //~^ WARN attempted to multiply with overflow let d = 42u8 - (42u8 + 1); //~^ WARN attempted to subtract with overflow - let _e = BLA; + let _e = [5u8][1]; + //~^ ERROR const index-expr is out of bounds black_box(a); black_box(b); black_box(c); diff --git a/src/test/compile-fail/const-eval-span.rs b/src/test/compile-fail/const-eval-span.rs index 44ab798f491..9fdd24c42fd 100644 --- a/src/test/compile-fail/const-eval-span.rs +++ b/src/test/compile-fail/const-eval-span.rs @@ -14,7 +14,7 @@ struct S(i32); const CONSTANT: S = S(0); -//~^ ERROR: constant evaluation error: call on struct [E0080] +//~^ ERROR: unimplemented constant expression: tuple struct constructors [E0080] enum E { V = CONSTANT, diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs index ecc43d21a46..4567cd4a74b 100644 --- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs +++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs @@ -17,12 +17,12 @@ enum Cake { use Cake::*; const BOO: (Cake, Cake) = (Marmor, BlackForest); -//~^ ERROR: constant evaluation error: non-constant path in constant expression [E0471] +//~^ ERROR: constant evaluation error: unimplemented constant expression: enum variants [E0471] const FOO: Cake = BOO.1; const fn foo() -> Cake { - Marmor //~ ERROR: constant evaluation error: non-constant path in constant expression [E0471] - //~^ ERROR: non-constant path in constant expression + Marmor //~ ERROR: constant evaluation error: unimplemented constant expression: enum variants + //~^ ERROR: unimplemented constant expression: enum variants } const WORKS: Cake = Marmor; diff --git a/src/test/compile-fail/feature-gate-negate-unsigned.rs b/src/test/compile-fail/feature-gate-negate-unsigned.rs index 4330a4cbeab..93e09c6d8d2 100644 --- a/src/test/compile-fail/feature-gate-negate-unsigned.rs +++ b/src/test/compile-fail/feature-gate-negate-unsigned.rs @@ -17,7 +17,8 @@ impl std::ops::Neg for S { } const _MAX: usize = -1; -//~^ ERROR unary negation of unsigned integer +//~^ WARN unary negation of unsigned integer +//~| ERROR unary negation of unsigned integer //~| HELP use a cast or the `!` operator fn main() { diff --git a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs index a7cabae16be..9564a080b8e 100644 --- a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs +++ b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs @@ -15,5 +15,5 @@ enum State { ST_NULL, ST_WHITESPACE } fn main() { [State::ST_NULL; (State::ST_WHITESPACE as usize)]; - //~^ ERROR expected constant integer for repeat count, but non-constant path + //~^ ERROR expected constant integer for repeat count, but unimplemented constant expression }