diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 45a90bf00681c..3f68f6aeccace 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -364,7 +364,7 @@ pub struct ConstEvalErr { pub kind: ErrKind, } -#[derive(Clone, PartialEq)] +#[derive(Clone)] pub enum ErrKind { CannotCast, CannotCastTo(&'static str), @@ -414,6 +414,7 @@ pub enum ErrKind { /// Expected, Got TypeMismatch(String, ConstInt), BadType(ConstVal), + ErroneousReferencedConstant(Box), } impl From for ErrKind { @@ -480,6 +481,7 @@ impl ConstEvalErr { expected, got.description()).into_cow() }, BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(), + ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(), } } } @@ -696,6 +698,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>, let val = match eval_const_expr_partial(tcx, &base, base_hint, fn_args) { Ok(val) => val, + Err(ConstEvalErr { kind: ErroneousReferencedConstant( + box ConstEvalErr { kind: TypeMismatch(_, val), .. }), .. }) | Err(ConstEvalErr { kind: TypeMismatch(_, val), .. }) => { // Something like `5i8 as usize` doesn't need a type hint for the base // instead take the type hint from the inner value @@ -737,19 +741,31 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>, } else { None }; - if let Some((e, ty)) = lookup_const_by_id(tcx, def_id, substs) { + if let Some((expr, ty)) = lookup_const_by_id(tcx, def_id, substs) { let item_hint = match ty { Some(ty) => ty_hint.checked_or(ty), None => ty_hint, }; - eval_const_expr_partial(tcx, e, item_hint, None)? + match eval_const_expr_partial(tcx, expr, item_hint, None) { + Ok(val) => val, + Err(err) => { + debug!("bad reference: {:?}, {:?}", err.description(), err.span); + signal!(e, ErroneousReferencedConstant(box err)) + }, + } } else { signal!(e, NonConstPath); } }, Def::Variant(enum_def, variant_def) => { if let Some(const_expr) = lookup_variant_by_id(tcx, enum_def, variant_def) { - eval_const_expr_partial(tcx, const_expr, ty_hint, None)? + match eval_const_expr_partial(tcx, const_expr, ty_hint, None) { + Ok(val) => val, + Err(err) => { + debug!("bad reference: {:?}, {:?}", err.description(), err.span); + signal!(e, ErroneousReferencedConstant(box err)) + }, + } } else { signal!(e, UnimplementedConstVal("enum variants")); } diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 085888dc21f64..9ab6a437a5ab2 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -29,6 +29,8 @@ #![feature(slice_patterns)] #![feature(iter_arith)] #![feature(question_mark)] +#![feature(box_patterns)] +#![feature(box_syntax)] #[macro_use] extern crate syntax; #[macro_use] extern crate log; diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 4659bb389dc6b..2fa7f026a521a 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -29,6 +29,7 @@ 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, UnimplementedConstVal}; +use rustc_const_eval::ErrKind::ErroneousReferencedConstant; use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; @@ -114,6 +115,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { match err.kind { UnimplementedConstVal(_) => {}, IndexOpFeatureGated => {}, + ErroneousReferencedConstant(_) => {}, _ => self.tcx.sess.add_lint(CONST_ERR, expr.id, expr.span, format!("constant evaluation error: {}. This will \ become a HARD ERROR in the future", diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 21122e7095dd1..674c3d6f9a17a 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -50,8 +50,9 @@ use middle::astconv_util::{prim_ty_to_ty, prohibit_type_params, prohibit_projection}; use middle::const_val::ConstVal; -use rustc_const_eval::eval_const_expr_partial; +use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr}; use rustc_const_eval::EvalHint::UncheckedExprHint; +use rustc_const_eval::ErrKind::ErroneousReferencedConstant; use hir::def::{self, Def}; use hir::def_id::DefId; use middle::resolve_lifetime as rl; @@ -1693,7 +1694,10 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, "expected usize value for array length, got {}", val.description()); this.tcx().types.err }, - Err(ref r) => { + // array length errors happen before the global constant check + // so we need to report the real error + Err(ConstEvalErr { kind: ErroneousReferencedConstant(box r), ..}) | + Err(r) => { let mut err = struct_span_err!(tcx.sess, r.span, E0250, "array length constant evaluation error: {}", r.description()); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2e1a684684375..1ec4e7b9d4644 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -68,7 +68,8 @@ use middle::lang_items::SizedTraitLangItem; use middle::resolve_lifetime; use middle::const_val::ConstVal; use rustc_const_eval::EvalHint::UncheckedExprHint; -use rustc_const_eval::eval_const_expr_partial; +use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr}; +use rustc_const_eval::ErrKind::ErroneousReferencedConstant; use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; @@ -1061,6 +1062,9 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>, print_err(tcx, e.span, ty_hint, cv); None }, + // enum variant evaluation happens before the global constant check + // so we need to report the real error + Err(ConstEvalErr { kind: ErroneousReferencedConstant(box err), ..}) | Err(err) => { let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error: {}", diff --git a/src/test/compile-fail/const-err-multi.rs b/src/test/compile-fail/const-err-multi.rs new file mode 100644 index 0000000000000..7de93a213b022 --- /dev/null +++ b/src/test/compile-fail/const-err-multi.rs @@ -0,0 +1,19 @@ +// 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. + +#![deny(const_err)] + +pub const A: i8 = -std::i8::MIN; //~ ERROR attempted to negate with overflow +pub const B: i8 = A; +pub const C: u8 = A as u8; +pub const D: i8 = 50 - A; + +fn main() { +}