Skip to content

don't report errors in constants at every use site #32877

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions src/librustc_const_eval/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ pub struct ConstEvalErr {
pub kind: ErrKind,
}

#[derive(Clone, PartialEq)]
#[derive(Clone)]
pub enum ErrKind {
CannotCast,
CannotCastTo(&'static str),
Expand Down Expand Up @@ -414,6 +414,7 @@ pub enum ErrKind {
/// Expected, Got
TypeMismatch(String, ConstInt),
BadType(ConstVal),
ErroneousReferencedConstant(Box<ConstEvalErr>),
}

impl From<ConstMathErr> for ErrKind {
Expand Down Expand Up @@ -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(),
}
}
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"));
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_const_eval/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_passes/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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",
Expand Down
8 changes: 6 additions & 2 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand Down
6 changes: 5 additions & 1 deletion src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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: {}",
Expand Down
19 changes: 19 additions & 0 deletions src/test/compile-fail/const-err-multi.rs
Original file line number Diff line number Diff line change
@@ -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() {
}