about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-04-13 22:33:10 -0700
committerbors <bors@rust-lang.org>2016-04-13 22:33:10 -0700
commit0cb2ee2ef6398296fbfd70ac5d71d9961955dc48 (patch)
tree6e7895e839800518e04baeaf567df6dd48c6d69c
parentadb0923492d737a4b3243db05f042e22a672b2d8 (diff)
parentd38a58d46d69bcd0b8839665fd1de9c34c09cfee (diff)
downloadrust-0cb2ee2ef6398296fbfd70ac5d71d9961955dc48.tar.gz
rust-0cb2ee2ef6398296fbfd70ac5d71d9961955dc48.zip
Auto merge of #32877 - oli-obk:const_err_multi, r=arielb1
don't report errors in constants at every use site

partially fixes #32842

r? @arielb1
cc @retep998

I chose this way of implementing it, because the alternative (checking if the error span is inside the constant's expressions's span) would get confusing when combined with expression generating macros.

A next step would be to re-enable the re-reporting of errors if the original erroneous constant is in another crate.
-rw-r--r--src/librustc_const_eval/eval.rs24
-rw-r--r--src/librustc_const_eval/lib.rs2
-rw-r--r--src/librustc_passes/consts.rs2
-rw-r--r--src/librustc_typeck/astconv.rs8
-rw-r--r--src/librustc_typeck/collect.rs6
-rw-r--r--src/test/compile-fail/const-err-multi.rs19
6 files changed, 54 insertions, 7 deletions
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 45a90bf0068..3f68f6aecca 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<ConstEvalErr>),
 }
 
 impl From<ConstMathErr> 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 085888dc21f..9ab6a437a5a 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 4659bb389dc..2fa7f026a52 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 21122e7095d..674c3d6f9a1 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 2e9c8676dc7..6d95586bed0 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};
@@ -1062,6 +1063,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 00000000000..7de93a213b0
--- /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 <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.
+
+#![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() {
+}