refactor constant evaluation error reporting

Refactor constant evaluation to use a single error reporting function
that reports a type-error-like message.

Also, unify all error codes with the "constant evaluation error" message
to just E0080, and similarly for a few other duplicate codes. The old
situation was a total mess, and now that we have *something* we can
further iterate on the UX.
This commit is contained in:
Ariel Ben-Yehuda 2016-07-20 00:02:56 +03:00
parent fa4eda8935
commit 37c569627c
55 changed files with 506 additions and 376 deletions

View File

@ -14,6 +14,7 @@ serialize = { path = "../libserialize" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_errors = { path = "../librustc_errors" }
syntax = { path = "../libsyntax" }
graphviz = { path = "../libgraphviz" }
syntax_pos = { path = "../libsyntax_pos" }

View File

@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal;
use ::{eval_const_expr, eval_const_expr_partial, compare_const_vals};
use ::{const_expr_to_pat, lookup_const_by_id};
use ::EvalHint::ExprTypeChecked;
use eval::report_const_eval_err;
use rustc::hir::def::*;
use rustc::hir::def_id::{DefId};
use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
@ -42,6 +43,7 @@ use syntax_pos::{Span, DUMMY_SP};
use rustc::hir::fold::{Folder, noop_fold_pat};
use rustc::hir::print::pat_to_string;
use syntax::ptr::P;
use rustc::util::common::ErrorReported;
use rustc::util::nodemap::FnvHashMap;
pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
@ -279,13 +281,7 @@ fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) {
Ok(_) => {}
Err(err) => {
let mut diag = struct_span_err!(cx.tcx.sess, err.span, E0471,
"constant evaluation error: {}",
err.description());
if !p.span.contains(err.span) {
diag.span_note(p.span, "in pattern here");
}
diag.emit();
report_const_eval_err(cx.tcx, &err, p.span, "pattern").emit();
}
}
}
@ -838,22 +834,19 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us
}
}
fn range_covered_by_constructor(ctor: &Constructor,
from: &ConstVal, to: &ConstVal) -> Option<bool> {
fn range_covered_by_constructor(tcx: TyCtxt, span: Span,
ctor: &Constructor,
from: &ConstVal, to: &ConstVal)
-> Result<bool, ErrorReported> {
let (c_from, c_to) = match *ctor {
ConstantValue(ref value) => (value, value),
ConstantRange(ref from, ref to) => (from, to),
Single => return Some(true),
Single => return Ok(true),
_ => bug!()
};
let cmp_from = compare_const_vals(c_from, from);
let cmp_to = compare_const_vals(c_to, to);
match (cmp_from, cmp_to) {
(Some(cmp_from), Some(cmp_to)) => {
Some(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
}
_ => None
}
let cmp_from = compare_const_vals(tcx, span, c_from, from)?;
let cmp_to = compare_const_vals(tcx, span, c_to, to)?;
Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
}
fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
@ -965,13 +958,12 @@ pub fn specialize<'a, 'b, 'tcx>(
Some(vec![(pat, Some(mt.ty))])
} else {
let expr_value = eval_const_expr(cx.tcx, &expr);
match range_covered_by_constructor(constructor, &expr_value, &expr_value) {
Some(true) => Some(vec![]),
Some(false) => None,
None => {
span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms");
None
}
match range_covered_by_constructor(
cx.tcx, expr.span, constructor, &expr_value, &expr_value
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
Err(ErrorReported) => None,
}
}
}
@ -979,13 +971,12 @@ pub fn specialize<'a, 'b, 'tcx>(
PatKind::Range(ref from, ref to) => {
let from_value = eval_const_expr(cx.tcx, &from);
let to_value = eval_const_expr(cx.tcx, &to);
match range_covered_by_constructor(constructor, &from_value, &to_value) {
Some(true) => Some(vec![]),
Some(false) => None,
None => {
span_err!(cx.tcx.sess, pat_span, E0299, "mismatched types between arms");
None
}
match range_covered_by_constructor(
cx.tcx, pat_span, constructor, &from_value, &to_value
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
Err(ErrorReported) => None,
}
}

View File

@ -551,6 +551,26 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases.
See also https://github.com/rust-lang/rust/issues/14587
"##,
E0080: r##"
This error indicates that the compiler was unable to sensibly evaluate an
constant expression that had to be evaluated. Attempting to divide by 0
or causing integer overflow are two ways to induce this error. For example:
```compile_fail
enum Enum {
X = (1 << 500),
Y = (1 / 0)
}
```
Ensure that the expressions given can be evaluated as the desired integer type.
See the FFI section of the Reference for more information about using a custom
integer type:
https://doc.rust-lang.org/reference.html#ffi-attributes
"##,
E0306: r##"
In an array literal `[x; N]`, `N` is the number of elements in the array. This
must be an unsigned integer. Erroneous code example:
@ -566,29 +586,11 @@ Working example:
let x = [0i32; 2];
```
"##,
E0307: r##"
The length of an array is part of its type. For this reason, this length must
be a compile-time constant. Erroneous code example:
```compile_fail
let len = 10;
let x = [0i32; len]; // error: expected constant integer for repeat count,
// found variable
```
Working example:
```
let x = [0i32; 10];
```
"##,
}
register_diagnostics! {
E0298, // mismatched types between arms
E0299, // mismatched types between arms
E0471, // constant evaluation error: ..
E0298, // cannot compare constants
// E0299, // mismatched types between arms
// E0471, // constant evaluation error (in pattern)
}

View File

@ -25,6 +25,7 @@ use rustc::hir::pat_util::def_to_path;
use rustc::ty::{self, Ty, TyCtxt, subst};
use rustc::ty::util::IntTypeExt;
use rustc::traits::ProjectionMode;
use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
use rustc::lint;
@ -43,6 +44,7 @@ use std::cmp::Ordering;
use std::collections::hash_map::Entry::Vacant;
use rustc_const_math::*;
use rustc_errors::{DiagnosticBuilder, check_old_school};
macro_rules! math {
($e:expr, $op:expr) => {
@ -338,20 +340,80 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Ok(P(hir::Pat { id: expr.id, node: pat, span: span }))
}
pub fn report_const_eval_err<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
err: &ConstEvalErr,
primary_span: Span,
primary_kind: &str)
-> DiagnosticBuilder<'tcx>
{
let mut err = err;
while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err {
err = i_err;
}
let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag);
diag
}
pub fn fatal_const_eval_err<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
err: &ConstEvalErr,
primary_span: Span,
primary_kind: &str)
-> !
{
report_const_eval_err(tcx, err, primary_span, primary_kind).emit();
tcx.sess.abort_if_errors();
unreachable!()
}
pub fn note_const_eval_err<'a, 'tcx>(
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
err: &ConstEvalErr,
primary_span: Span,
primary_kind: &str,
diag: &mut DiagnosticBuilder)
{
match err.description() {
ConstEvalErrDescription::Simple(message) => {
if check_old_school() {
diag.note(&message);
} else {
diag.span_label(err.span, &message);
}
}
ConstEvalErrDescription::ExpectedFound { error, expected, found } => {
if check_old_school() {
diag.note(&error);
} else {
diag.span_label(err.span, &error);
}
diag.note(&format!("expected `{}`", expected));
diag.note(&format!("found `{}`", found));
}
}
if !primary_span.contains(err.span) {
diag.span_note(primary_span,
&format!("for {} here", primary_kind));
}
}
pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
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(s) => {
report_const_eval_err(tcx, &s, e.span, "expression").emit();
match s.kind {
NonConstPath |
UnimplementedConstVal(_) => tcx.sess.span_fatal(s.span, &s.description()),
_ => {
tcx.sess.span_err(s.span, &s.description());
Dummy
}
UnimplementedConstVal(_) => tcx.sess.abort_if_errors(),
_ => {}
}
Dummy
},
}
}
@ -400,6 +462,7 @@ pub enum ErrKind {
IntermediateUnsignedNegative,
/// Expected, Got
TypeMismatch(String, ConstInt),
BadType(ConstVal),
ErroneousReferencedConstant(Box<ConstEvalErr>),
CharCast(ConstInt),
@ -411,57 +474,96 @@ impl From<ConstMathErr> for ErrKind {
}
}
#[derive(Clone, Debug)]
pub enum ConstEvalErrDescription<'a> {
Simple(Cow<'a, str>),
ExpectedFound {
error: Cow<'a, str>,
expected: Cow<'a, str>,
found: Cow<'a, str>
}
}
impl<'a> ConstEvalErrDescription<'a> {
/// Return a one-line description of the error, for lints and such
pub fn into_oneline(self) -> Cow<'a, str> {
match self {
ConstEvalErrDescription::Simple(simple) => simple,
ConstEvalErrDescription::ExpectedFound {
error,
expected,
found
} => {
format!("{}: expected `{}`, found `{}`", error, expected, found)
.into_cow()
}
}
}
}
impl ConstEvalErr {
pub fn description(&self) -> Cow<str> {
pub fn description(&self) -> ConstEvalErrDescription {
use self::ErrKind::*;
use self::ConstEvalErrDescription::*;
macro_rules! simple {
($msg:expr) => ({ Simple($msg.into_cow()) });
($fmt:expr, $($arg:tt)+) => ({
Simple(format!($fmt, $($arg)+).into_cow())
})
}
match self.kind {
CannotCast => "can't cast this type".into_cow(),
CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(),
InvalidOpForInts(_) => "can't do this op on integrals".into_cow(),
InvalidOpForBools(_) => "can't do this op on bools".into_cow(),
InvalidOpForFloats(_) => "can't do this op on floats".into_cow(),
InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(),
InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(),
NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(),
NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(),
CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(),
CannotCast => simple!("can't cast this type"),
CannotCastTo(s) => simple!("can't cast this type to {}", s),
InvalidOpForInts(_) => simple!("can't do this op on integrals"),
InvalidOpForBools(_) => simple!("can't do this op on bools"),
InvalidOpForFloats(_) => simple!("can't do this op on floats"),
InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"),
InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"),
NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
NotOn(ref const_val) => simple!("not on {}", const_val.description()),
CallOn(ref const_val) => simple!("call on {}", const_val.description()),
MissingStructField => "nonexistent struct field".into_cow(),
NonConstPath => "non-constant path in constant expression".into_cow(),
MissingStructField => simple!("nonexistent struct field"),
NonConstPath => simple!("non-constant path in constant expression"),
UnimplementedConstVal(what) =>
format!("unimplemented constant expression: {}", what).into_cow(),
UnresolvedPath => "unresolved path in constant expression".into_cow(),
ExpectedConstTuple => "expected constant tuple".into_cow(),
ExpectedConstStruct => "expected constant struct".into_cow(),
TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
IndexedNonVec => "indexing is only supported for arrays".into_cow(),
IndexNegative => "indices must be non-negative integers".into_cow(),
IndexNotInt => "indices must be integers".into_cow(),
simple!("unimplemented constant expression: {}", what),
UnresolvedPath => simple!("unresolved path in constant expression"),
ExpectedConstTuple => simple!("expected constant tuple"),
ExpectedConstStruct => simple!("expected constant struct"),
TupleIndexOutOfBounds => simple!("tuple index out of bounds"),
IndexedNonVec => simple!("indexing is only supported for arrays"),
IndexNegative => simple!("indices must be non-negative integers"),
IndexNotInt => simple!("indices must be integers"),
IndexOutOfBounds { len, index } => {
format!("index out of bounds: the len is {} but the index is {}",
len, index).into_cow()
simple!("index out of bounds: the len is {} but the index is {}",
len, index)
}
RepeatCountNotNatural => "repeat count must be a natural number".into_cow(),
RepeatCountNotInt => "repeat count must be integers".into_cow(),
RepeatCountNotNatural => simple!("repeat count must be a natural number"),
RepeatCountNotInt => simple!("repeat count must be integers"),
MiscBinaryOp => "bad operands for binary".into_cow(),
MiscCatchAll => "unsupported constant expr".into_cow(),
IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(),
Math(ref err) => err.description().into_cow(),
MiscBinaryOp => simple!("bad operands for binary"),
MiscCatchAll => simple!("unsupported constant expr"),
IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
Math(ref err) => Simple(err.description().into_cow()),
IntermediateUnsignedNegative => "during the computation of an unsigned a negative \
number was encountered. This is most likely a bug in\
the constant evaluator".into_cow(),
IntermediateUnsignedNegative => simple!(
"during the computation of an unsigned a negative \
number was encountered. This is most likely a bug in\
the constant evaluator"),
TypeMismatch(ref expected, ref got) => {
format!("mismatched types: expected `{}`, found `{}`",
expected, got.description()).into_cow()
ExpectedFound {
error: "mismatched types".into_cow(),
expected: <&str>::into_cow(expected),
found: got.description().into_cow()
}
},
BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(),
ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(),
BadType(ref i) => simple!("value of wrong type: {:?}", i),
ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
CharCast(ref got) => {
format!("only `u8` can be cast as `char`, not `{}`", got.description()).into_cow()
simple!("only `u8` can be cast as `char`, not `{}`", got.description())
},
}
}
@ -1185,8 +1287,10 @@ fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>, span: Span) -> ConstFl
})
}
pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
match (a, b) {
pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
-> Result<Ordering, ErrorReported>
{
let result = match (a, b) {
(&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
(&Float(a), &Float(b)) => a.try_cmp(b).ok(),
(&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
@ -1194,62 +1298,82 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
(&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
(&Char(a), &Char(ref b)) => Some(a.cmp(b)),
_ => None,
};
match result {
Some(result) => Ok(result),
None => {
// FIXME: can this ever be reached?
span_err!(tcx.sess, span, E0298,
"type mismatch comparing {} and {}",
a.description(),
b.description());
Err(ErrorReported)
}
}
}
pub fn compare_lit_exprs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
span: Span,
a: &Expr,
b: &Expr) -> Option<Ordering> {
b: &Expr) -> Result<Ordering, ErrorReported> {
let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) {
Ok(a) => a,
Err(e) => {
tcx.sess.span_err(a.span, &e.description());
return None;
report_const_eval_err(tcx, &e, a.span, "expression").emit();
return Err(ErrorReported);
}
};
let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) {
Ok(b) => b,
Err(e) => {
tcx.sess.span_err(b.span, &e.description());
return None;
report_const_eval_err(tcx, &e, b.span, "expression").emit();
return Err(ErrorReported);
}
};
compare_const_vals(&a, &b)
compare_const_vals(tcx, span, &a, &b)
}
/// Returns the repeat count for a repeating vector expression.
pub fn eval_repeat_count<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
count_expr: &hir::Expr) -> usize {
/// Returns the value of the length-valued expression
pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
count_expr: &hir::Expr,
reason: &str)
-> Result<usize, ErrorReported>
{
let hint = UncheckedExprHint(tcx.types.usize);
match eval_const_expr_partial(tcx, count_expr, hint, None) {
Ok(Integral(Usize(count))) => {
let val = count.as_u64(tcx.sess.target.uint_type);
assert_eq!(val as usize as u64, val);
val as usize
Ok(val as usize)
},
Ok(const_val) => {
span_err!(tcx.sess, count_expr.span, E0306,
"expected positive integer for repeat count, found {}",
"expected usize for {}, found {}",
reason,
const_val.description());
0
Err(ErrorReported)
}
Err(err) => {
let err_msg = match count_expr.node {
let mut diag = report_const_eval_err(
tcx, &err, count_expr.span, reason);
match count_expr.node {
hir::ExprPath(None, hir::Path {
global: false,
ref segments,
..
}) if segments.len() == 1 =>
format!("found variable"),
_ => match err.kind {
MiscCatchAll => format!("but found {}", err.description()),
_ => format!("but {}", err.description())
}) if segments.len() == 1 => {
if let Some(Def::Local(..)) = tcx.expect_def_or_none(count_expr.id) {
diag.note(&format!("`{}` is a variable", segments[0].name));
}
}
};
span_err!(tcx.sess, count_expr.span, E0307,
"expected constant integer for repeat count, {}", err_msg);
0
_ => {}
}
diag.emit();
Err(ErrorReported)
}
}
}

View File

@ -36,6 +36,7 @@
#[macro_use] extern crate rustc;
extern crate rustc_back;
extern crate rustc_const_math;
extern crate rustc_errors;
extern crate graphviz;
extern crate syntax_pos;
extern crate serialize as rustc_serialize; // used by deriving

View File

@ -40,6 +40,7 @@ use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::traits::ProjectionMode;
use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
use rustc::middle::const_qualif::ConstQualif;
use rustc::lint::builtin::CONST_ERR;
@ -116,7 +117,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
_ => 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())),
err.description().into_oneline())),
}
}
self.with_mode(mode, |this| {
@ -211,15 +212,6 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
}
}
}
fn msg(&self) -> &'static str {
match self.mode {
Mode::Const => "constant",
Mode::ConstFn => "constant function",
Mode::StaticMut | Mode::Static => "static",
Mode::Var => bug!(),
}
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
@ -289,18 +281,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
self.global_expr(Mode::Const, &start);
self.global_expr(Mode::Const, &end);
match compare_lit_exprs(self.tcx, start, end) {
Some(Ordering::Less) |
Some(Ordering::Equal) => {}
Some(Ordering::Greater) => {
match compare_lit_exprs(self.tcx, p.span, start, end) {
Ok(Ordering::Less) |
Ok(Ordering::Equal) => {}
Ok(Ordering::Greater) => {
span_err!(self.tcx.sess, start.span, E0030,
"lower range bound must be less than or equal to upper");
}
None => {
span_err!(self.tcx.sess, p.span, E0014,
"paths in {}s may only refer to constants",
self.msg());
}
Err(ErrorReported) => {}
}
}
_ => intravisit::walk_pat(self, p)
@ -429,7 +417,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
Err(msg) => {
self.tcx.sess.add_lint(CONST_ERR, ex.id,
msg.span,
msg.description().into_owned())
msg.description().into_oneline().into_owned())
}
}
}

View File

@ -11,7 +11,7 @@
#![allow(non_snake_case)]
register_long_diagnostics! {
/*
E0014: r##"
Constants can only be initialized by a constant value or, in a future
version of Rust, a call to a const function. This error indicates the use
@ -30,7 +30,7 @@ const FOO: i32 = { const X : i32 = 0; X };
const FOO2: i32 = { 0 }; // but brackets are useless here
```
"##,
*/
E0030: r##"
When matching against a range, the compiler verifies that the range is
non-empty. Range patterns include both end-points, so this is equivalent to

View File

@ -190,7 +190,7 @@ use self::FailureHandler::*;
use llvm::{ValueRef, BasicBlockRef};
use rustc_const_eval::check_match::{self, Constructor, StaticInliner};
use rustc_const_eval::{compare_lit_exprs, eval_const_expr};
use rustc_const_eval::{compare_lit_exprs, eval_const_expr, fatal_const_eval_err};
use rustc::hir::def::{Def, DefMap};
use rustc::hir::def_id::DefId;
use middle::expr_use_visitor as euv;
@ -239,9 +239,9 @@ struct ConstantExpr<'a>(&'a hir::Expr);
impl<'a> ConstantExpr<'a> {
fn eq<'b, 'tcx>(self, other: ConstantExpr<'a>, tcx: TyCtxt<'b, 'tcx, 'tcx>) -> bool {
match compare_lit_exprs(tcx, self.0, other.0) {
Some(result) => result == Ordering::Equal,
None => bug!("compare_list_exprs: type mismatch"),
match compare_lit_exprs(tcx, self.0.span, self.0, other.0) {
Ok(result) => result == Ordering::Equal,
Err(_) => bug!("compare_list_exprs: type mismatch"),
}
}
}
@ -288,7 +288,9 @@ impl<'a, 'b, 'tcx> Opt<'a, 'tcx> {
let expr = consts::const_expr(ccx, &lit_expr, bcx.fcx.param_substs, None, Yes);
let llval = match expr {
Ok((llval, _)) => llval,
Err(err) => bcx.ccx().sess().span_fatal(lit_expr.span, &err.description()),
Err(err) => {
fatal_const_eval_err(bcx.tcx(), err.as_inner(), lit_expr.span, "pattern");
}
};
let lit_datum = immediate_rvalue(llval, lit_ty);
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
@ -297,11 +299,11 @@ impl<'a, 'b, 'tcx> Opt<'a, 'tcx> {
ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => {
let l1 = match consts::const_expr(ccx, &l1, bcx.fcx.param_substs, None, Yes) {
Ok((l1, _)) => l1,
Err(err) => bcx.ccx().sess().span_fatal(l1.span, &err.description()),
Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l1.span, "pattern"),
};
let l2 = match consts::const_expr(ccx, &l2, bcx.fcx.param_substs, None, Yes) {
Ok((l2, _)) => l2,
Err(err) => bcx.ccx().sess().span_fatal(l2.span, &err.description()),
Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l2.span, "pattern"),
};
RangeResult(Result::new(bcx, l1), Result::new(bcx, l2))
}

View File

@ -14,7 +14,7 @@ use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
use llvm::{InternalLinkage, ValueRef, Bool, True};
use middle::const_qualif::ConstQualif;
use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind};
use rustc_const_eval::eval_repeat_count;
use rustc_const_eval::{eval_length, report_const_eval_err, note_const_eval_err};
use rustc::hir::def::Def;
use rustc::hir::def_id::DefId;
use rustc::hir::map as hir_map;
@ -44,7 +44,6 @@ use rustc_const_math::{ConstInt, ConstUsize, ConstIsize};
use rustc::hir;
use std::ffi::{CStr, CString};
use std::borrow::Cow;
use libc::c_uint;
use syntax::ast::{self, LitKind};
use syntax::attr::{self, AttrMetaMethods};
@ -250,10 +249,11 @@ impl ConstEvalFailure {
Compiletime(e) => e,
}
}
pub fn description(&self) -> Cow<str> {
pub fn as_inner(&self) -> &ConstEvalErr {
match self {
&Runtime(ref e) => e.description(),
&Compiletime(ref e) => e.description(),
&Runtime(ref e) => e,
&Compiletime(ref e) => e,
}
}
}
@ -274,7 +274,7 @@ fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let empty_substs = ccx.tcx().mk_substs(Substs::empty());
match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) {
Err(Runtime(err)) => {
ccx.tcx().sess.span_err(expr.span, &err.description());
report_const_eval_err(ccx.tcx(), &err, expr.span, "expression").emit();
Err(Compiletime(err))
},
other => other,
@ -526,12 +526,15 @@ pub fn const_err<T>(cx: &CrateContext,
(Ok(x), _) => Ok(x),
(Err(err), TrueConst::Yes) => {
let err = ConstEvalErr{ span: span, kind: err };
cx.tcx().sess.span_err(span, &err.description());
report_const_eval_err(cx.tcx(), &err, span, "expression").emit();
Err(Compiletime(err))
},
(Err(err), TrueConst::No) => {
let err = ConstEvalErr{ span: span, kind: err };
cx.tcx().sess.span_warn(span, &err.description());
let mut diag = cx.tcx().sess.struct_span_warn(
span, "this expression will panic at run-time");
note_const_eval_err(cx.tcx(), &err, span, "expression", &mut diag);
diag.emit();
Err(Runtime(err))
},
}
@ -875,7 +878,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
hir::ExprRepeat(ref elem, ref count) => {
let unit_ty = ety.sequence_element_type(cx.tcx());
let llunitty = type_of::type_of(cx, unit_ty);
let n = eval_repeat_count(cx.tcx(), count);
let n = eval_length(cx.tcx(), count, "repeat count").unwrap();
let unit_val = const_expr(cx, &elem, param_substs, fn_args, trueconst)?.0;
let vs = vec![unit_val; n];
if val_ty(unit_val) != llunitty {

View File

@ -44,6 +44,7 @@ use syntax::ptr::P;
use syntax::parse::token;
use rustc::session::Session;
use rustc_const_eval::fatal_const_eval_err;
use syntax_pos::{Span, DUMMY_SP};
use std::cmp::Ordering;
@ -1408,7 +1409,10 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
// this should probably help simd error reporting
consts::TrueConst::Yes) {
Ok((vector, _)) => vector,
Err(err) => bcx.sess().span_fatal(span, &err.description()),
Err(err) => {
fatal_const_eval_err(bcx.tcx(), err.as_inner(), span,
"shuffle indices");
}
}
}
None => llargs[2]

View File

@ -925,7 +925,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
Err(ConstEvalFailure::Runtime(err)) => {
span_bug!(constant.span,
"MIR constant {:?} results in runtime panic: {}",
"MIR constant {:?} results in runtime panic: {:?}",
constant, err.description())
}
}

View File

@ -29,6 +29,7 @@ use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::subst;
use rustc::dep_graph::DepNode;
use rustc_const_eval::fatal_const_eval_err;
use std::hash::{Hash, Hasher};
use syntax::ast::{self, NodeId};
use syntax::{attr,errors};
@ -81,7 +82,11 @@ impl<'a, 'tcx> TransItem<'tcx> {
if let hir::ItemStatic(_, m, ref expr) = item.node {
match consts::trans_static(&ccx, m, expr, item.id, &item.attrs) {
Ok(_) => { /* Cool, everything's alright. */ },
Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()),
Err(err) => {
// FIXME: shouldn't this be a `span_err`?
fatal_const_eval_err(
ccx.tcx(), &err, expr.span, "static");
}
};
} else {
span_bug!(item.span, "Mismatch between hir::Item type and TransItem type")

View File

@ -30,7 +30,7 @@ use value::Value;
use rustc::ty::{self, Ty};
use rustc::hir;
use rustc_const_eval::eval_repeat_count;
use rustc_const_eval::eval_length;
use syntax::ast;
use syntax::parse::token::InternedString;
@ -218,7 +218,7 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
return expr::trans_into(bcx, &element, Ignore);
}
SaveIn(lldest) => {
match eval_repeat_count(bcx.tcx(), &count_expr) {
match eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() {
0 => expr::trans_into(bcx, &element, Ignore),
1 => expr::trans_into(bcx, &element, SaveIn(lldest)),
count => {
@ -268,7 +268,7 @@ fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize {
},
hir::ExprVec(ref es) => es.len(),
hir::ExprRepeat(_, ref count_expr) => {
eval_repeat_count(bcx.tcx(), &count_expr)
eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap()
}
_ => span_bug!(content_expr.span, "unexpected vec content")
}

View File

@ -48,10 +48,7 @@
//! case but `&a` in the second. Basically, defaults that appear inside
//! an rptr (`&r.T`) use the region `r` that appears in the rptr.
use middle::const_val::ConstVal;
use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
use rustc_const_eval::EvalHint::UncheckedExprHint;
use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
use rustc_const_eval::eval_length;
use hir::{self, SelfKind};
use hir::def::{Def, PathResolution};
use hir::def_id::DefId;
@ -70,7 +67,6 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::{NodeMap, FnvHashSet};
use rustc_const_math::ConstInt;
use std::cell::RefCell;
use syntax::{abi, ast};
use syntax::feature_gate::{GateIssue, emit_feature_err};
@ -1741,33 +1737,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
ty
}
hir::TyFixedLengthVec(ref ty, ref e) => {
let hint = UncheckedExprHint(tcx.types.usize);
match eval_const_expr_partial(tcx.global_tcx(), &e, hint, None) {
Ok(ConstVal::Integral(ConstInt::Usize(i))) => {
let i = i.as_u64(tcx.sess.target.uint_type);
assert_eq!(i as usize as u64, i);
tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), i as usize)
},
Ok(val) => {
span_err!(tcx.sess, ast_ty.span, E0249,
"expected usize value for array length, got {}",
val.description());
self.tcx().types.err
},
// 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());
if !ast_ty.span.contains(r.span) {
span_note!(&mut err, ast_ty.span, "for array length here")
}
err.emit();
self.tcx().types.err
}
if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") {
tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
} else {
self.tcx().types.err
}
}
hir::TyTypeof(ref _e) => {

View File

@ -126,7 +126,7 @@ use rustc::hir::intravisit::{self, Visitor};
use rustc::hir::{self, PatKind};
use rustc::hir::print as pprust;
use rustc_back::slice;
use rustc_const_eval::eval_repeat_count;
use rustc_const_eval::eval_length;
mod assoc;
mod autoderef;
@ -3539,7 +3539,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
hir::ExprRepeat(ref element, ref count_expr) => {
self.check_expr_has_type(&count_expr, tcx.types.usize);
let count = eval_repeat_count(self.tcx.global_tcx(), &count_expr);
let count = eval_length(self.tcx.global_tcx(), &count_expr, "repeat count")
.unwrap_or(0);
let uty = match expected {
ExpectHasType(uty) => {

View File

@ -66,8 +66,7 @@ use constrained_type_params as ctp;
use middle::lang_items::SizedTraitLangItem;
use middle::const_val::ConstVal;
use rustc_const_eval::EvalHint::UncheckedExprHint;
use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err};
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};
@ -1091,14 +1090,9 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
},
// 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!(ccx.tcx.sess, err.span, E0080,
"constant evaluation error: {}",
err.description());
if !e.span.contains(err.span) {
diag.span_note(e.span, "for enum discriminant here");
}
let mut diag = report_const_eval_err(
ccx.tcx, &err, e.span, "enum discriminant");
diag.emit();
None
}

View File

@ -1079,25 +1079,6 @@ impl Foo {
```
"##,
E0080: r##"
This error indicates that the compiler was unable to sensibly evaluate an
integer expression provided as an enum discriminant. Attempting to divide by 0
or causing integer overflow are two ways to induce this error. For example:
```compile_fail
enum Enum {
X = (1 << 500),
Y = (1 / 0)
}
```
Ensure that the expressions given can be evaluated as the desired integer type.
See the FFI section of the Reference for more information about using a custom
integer type:
https://doc.rust-lang.org/reference.html#ffi-attributes
"##,
E0081: r##"
Enum discriminants are used to differentiate enum variants stored in memory.
This error indicates that the same value was used for two or more variants,
@ -2970,38 +2951,6 @@ not a distinct static type. Likewise, it's not legal to attempt to
behavior for specific enum variants.
"##,
E0249: r##"
This error indicates a constant expression for the array length was found, but
it was not an integer (signed or unsigned) expression.
Some examples of code that produces this error are:
```compile_fail
const A: [u32; "hello"] = []; // error
const B: [u32; true] = []; // error
const C: [u32; 0.0] = []; // error
"##,
E0250: r##"
There was an error while evaluating the expression for the length of a fixed-
size array type.
Some examples of this error are:
```compile_fail
// divide by zero in the length expression
const A: [u32; 1/0] = [];
// Rust currently will not evaluate the function `foo` at compile time
fn foo() -> usize { 12 }
const B: [u32; foo()] = [];
// it is an error to try to add `u8` and `f64`
use std::{f64, u8};
const C: [u32; u8::MAX + f64::EPSILON] = [];
```
"##,
E0318: r##"
Default impls for a trait must be located in the same crate where the trait was
defined. For more information see the [opt-in builtin traits RFC](https://github
@ -4088,6 +4037,7 @@ register_diagnostics! {
E0245, // not a trait
// E0246, // invalid recursive type
// E0247,
// E0249,
// E0319, // trait impls for defaulted traits allowed just for structs/enums
E0320, // recursive overflow during dropck
E0328, // cannot implement Unsize explicitly

1
src/rustc/Cargo.lock generated
View File

@ -105,6 +105,7 @@ dependencies = [
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_const_math 0.0.0",
"rustc_errors 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",

View File

@ -10,7 +10,8 @@
const A: &'static [i32] = &[];
const B: i32 = (&A)[1];
//~^ ERROR index out of bounds: the len is 0 but the index is 1
//~^ ERROR constant evaluation error
//~| index out of bounds: the len is 0 but the index is 1
fn main() {
let _ = B;

View File

@ -10,7 +10,8 @@
const A: [i32; 0] = [];
const B: i32 = A[1];
//~^ ERROR index out of bounds: the len is 0 but the index is 1
//~^ ERROR constant evaluation error
//~| index out of bounds: the len is 0 but the index is 1
fn main() {
let _ = B;

View File

@ -14,7 +14,7 @@ trait Foo {
const ID: usize;
}
const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0250
const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0080
fn main() {
assert_eq!(1, X);

View File

@ -25,7 +25,8 @@ impl Foo for Def {
}
pub fn test<A: Foo, B: Foo>() {
let _array = [4; <A as Foo>::Y]; //~ error: expected constant integer
let _array = [4; <A as Foo>::Y]; //~ ERROR E0080
//~| non-constant path in constant
}
fn main() {

View File

@ -16,7 +16,8 @@ const FOO: [u32; 3] = [1, 2, 3];
const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval
const BLUB: [u32; FOO[4]] = [5, 6];
//~^ ERROR array length constant evaluation error: index out of bounds: the len is 3 but the index is 4 [E0250]
//~^ ERROR constant evaluation error [E0080]
//~| index out of bounds: the len is 3 but the index is 4
fn main() {
let _ = BAR;

View File

@ -15,5 +15,6 @@ fn f(x: usize) -> usize {
}
fn main() {
let _ = [0; f(2)]; //~ ERROR: non-constant path in constant expression [E0307]
let _ = [0; f(2)]; //~ ERROR constant evaluation error [E0080]
//~| non-constant path in constant expression
}

View File

@ -22,21 +22,29 @@ fn black_box<T>(_: T) {
// Make sure that the two uses get two errors.
const FOO: u8 = [5u8][1];
//~^ ERROR index out of bounds: the len is 1 but the index is 1
//~^^ ERROR index out of bounds: the len is 1 but the index is 1
//~^ ERROR constant evaluation error
//~| index out of bounds: the len is 1 but the index is 1
//~^^^ ERROR constant evaluation error
//~| index out of bounds: the len is 1 but the index is 1
fn main() {
let a = -std::i8::MIN;
//~^ WARN attempted to negate with overflow
//~^ WARN this expression will panic at run-time
//~| attempted to negate with overflow
let b = 200u8 + 200u8 + 200u8;
//~^ WARN attempted to add with overflow
//~| WARN attempted to add with overflow
//~^ WARN this expression will panic at run-time
//~| attempted to add with overflow
//~^^^ WARN this expression will panic at run-time
//~| attempted to add with overflow
let c = 200u8 * 4;
//~^ WARN attempted to multiply with overflow
//~^ WARN this expression will panic at run-time
//~| attempted to multiply with overflow
let d = 42u8 - (42u8 + 1);
//~^ WARN attempted to subtract with overflow
//~^ WARN this expression will panic at run-time
//~| attempted to subtract with overflow
let _e = [5u8][1];
//~^ WARN index out of bounds: the len is 1 but the index is 1
//~^ WARN this expression will panic at run-time
//~| index out of bounds: the len is 1 but the index is 1
black_box(a);
black_box(b);
black_box(c);

View File

@ -19,13 +19,16 @@ use std::{u8, u16, u32, u64, usize};
const NEG_128: i8 = -128;
const NEG_NEG_128: i8 = -NEG_128;
//~^ ERROR constant evaluation error: attempted to negate with overflow
//~| ERROR attempted to negate with overflow
//~| ERROR attempted to negate with overflow
//~^ ERROR constant evaluation error
//~| attempted to negate with overflow
//~| ERROR constant evaluation error
//~| attempted to negate with overflow
//~| ERROR constant evaluation error
//~| attempted to negate with overflow
fn main() {
match -128i8 {
NEG_NEG_128 => println!("A"), //~ NOTE in pattern here
NEG_NEG_128 => println!("A"), //~ NOTE for pattern here
_ => println!("B"),
}
}

View File

@ -17,7 +17,7 @@
// self-hosted and a cross-compiled setup; therefore resorting to
// error-pattern for now.
// error-pattern: expected constant integer for repeat count, but attempted to add with overflow
// error-pattern: attempted to add with overflow
#![allow(unused_imports)]

View File

@ -20,9 +20,10 @@ use std::{u8, u16, u32, u64, usize};
const A_I8_T
: [u32; (i8::MAX as i8 + 1u8) as usize]
//~^ ERROR mismatched types:
//~| expected `i8`,
//~| found `u8` [E0250]
//~^ ERROR constant evaluation error [E0080]
//~| mismatched types
//~| expected `i8`
//~| found `u8`
= [0; (i8::MAX as usize) + 1];
@ -33,7 +34,8 @@ const A_CHAR_USIZE
const A_BAD_CHAR_USIZE
: [u32; 5i8 as char as usize]
//~^ ERROR only `u8` can be cast as `char`, not `i8`
//~^ ERROR constant evaluation error
//~| only `u8` can be cast as `char`, not `i8`
= [0; 5];
fn main() {}

View File

@ -21,86 +21,114 @@ use std::{u8, u16, u32, u64, usize};
const VALS_I8: (i8, i8, i8, i8) =
(-i8::MIN,
//~^ ERROR attempted to negate with overflow
//~^ ERROR constant evaluation error
//~| attempted to negate with overflow
i8::MIN - 1,
//~^ ERROR attempted to subtract with overflow
//~^ ERROR constant evaluation error
//~| attempted to subtract with overflow
i8::MAX + 1,
//~^ ERROR attempted to add with overflow
//~^ ERROR constant evaluation error
//~| attempted to add with overflow
i8::MIN * 2,
//~^ ERROR attempted to multiply with overflow
//~^ ERROR constant evaluation error
//~| attempted to multiply with overflow
);
const VALS_I16: (i16, i16, i16, i16) =
(-i16::MIN,
//~^ ERROR attempted to negate with overflow
//~^ ERROR constant evaluation error
//~| attempted to negate with overflow
i16::MIN - 1,
//~^ ERROR attempted to subtract with overflow
//~^ ERROR constant evaluation error
//~| attempted to subtract with overflow
i16::MAX + 1,
//~^ ERROR attempted to add with overflow
//~^ ERROR constant evaluation error
//~| attempted to add with overflow
i16::MIN * 2,
//~^ ERROR attempted to multiply with overflow
//~^ ERROR constant evaluation error
//~| attempted to multiply with overflow
);
const VALS_I32: (i32, i32, i32, i32) =
(-i32::MIN,
//~^ ERROR attempted to negate with overflow
//~^ ERROR constant evaluation error
//~| attempted to negate with overflow
i32::MIN - 1,
//~^ ERROR attempted to subtract with overflow
//~^ ERROR constant evaluation error
//~| attempted to subtract with overflow
i32::MAX + 1,
//~^ ERROR attempted to add with overflow
//~^ ERROR constant evaluation error
//~| attempted to add with overflow
i32::MIN * 2,
//~^ ERROR attempted to multiply with overflow
//~^ ERROR constant evaluation error
//~| attempted to multiply with overflow
);
const VALS_I64: (i64, i64, i64, i64) =
(-i64::MIN,
//~^ ERROR attempted to negate with overflow
//~^ ERROR constant evaluation error
//~| attempted to negate with overflow
i64::MIN - 1,
//~^ ERROR attempted to subtract with overflow
//~^ ERROR constant evaluation error
//~| attempted to subtract with overflow
i64::MAX + 1,
//~^ ERROR attempted to add with overflow
//~^ ERROR constant evaluation error
//~| attempted to add with overflow
i64::MAX * 2,
//~^ ERROR attempted to multiply with overflow
//~^ ERROR constant evaluation error
//~| attempted to multiply with overflow
);
const VALS_U8: (u8, u8, u8, u8) =
(-(u8::MIN as i8) as u8,
u8::MIN - 1,
//~^ ERROR attempted to subtract with overflow
//~^ ERROR constant evaluation error
//~| attempted to subtract with overflow
u8::MAX + 1,
//~^ ERROR attempted to add with overflow
//~^ ERROR constant evaluation error
//~| attempted to add with overflow
u8::MAX * 2,
//~^ ERROR attempted to multiply with overflow
//~^ ERROR constant evaluation error
//~| attempted to multiply with overflow
);
const VALS_U16: (u16, u16, u16, u16) =
(-(u16::MIN as i16) as u16,
u16::MIN - 1,
//~^ ERROR attempted to subtract with overflow
//~^ ERROR constant evaluation error
//~| attempted to subtract with overflow
u16::MAX + 1,
//~^ ERROR attempted to add with overflow
//~^ ERROR constant evaluation error
//~| attempted to add with overflow
u16::MAX * 2,
//~^ ERROR attempted to multiply with overflow
//~^ ERROR constant evaluation error
//~| attempted to multiply with overflow
);
const VALS_U32: (u32, u32, u32, u32) =
(-(u32::MIN as i32) as u32,
u32::MIN - 1,
//~^ ERROR attempted to subtract with overflow
//~^ ERROR constant evaluation error
//~| attempted to subtract with overflow
u32::MAX + 1,
//~^ ERROR attempted to add with overflow
//~^ ERROR constant evaluation error
//~| attempted to add with overflow
u32::MAX * 2,
//~^ ERROR attempted to multiply with overflow
//~^ ERROR constant evaluation error
//~| attempted to multiply with overflow
);
const VALS_U64: (u64, u64, u64, u64) =
(-(u64::MIN as i64) as u64,
u64::MIN - 1,
//~^ ERROR attempted to subtract with overflow
//~^ ERROR constant evaluation error
//~| attempted to subtract with overflow
u64::MAX + 1,
//~^ ERROR attempted to add with overflow
//~^ ERROR constant evaluation error
//~| attempted to add with overflow
u64::MAX * 2,
//~^ ERROR attempted to multiply with overflow
//~^ ERROR constant evaluation error
//~| attempted to multiply with overflow
);
fn main() {

View File

@ -14,7 +14,8 @@
struct S(i32);
const CONSTANT: S = S(0);
//~^ ERROR: unimplemented constant expression: tuple struct constructors [E0080]
//~^ ERROR E0080
//~| unimplemented constant expression: tuple struct constructors
enum E {
V = CONSTANT,

View File

@ -17,10 +17,11 @@ const fn f(x: usize) -> usize {
for i in 0..x {
sum += i;
}
sum //~ ERROR: E0250
sum //~ ERROR E0080
//~| non-constant path in constant
}
#[allow(unused_variables)]
fn main() {
let a : [i32; f(X)];
let a : [i32; f(X)]; //~ NOTE for array length here
}

View File

@ -9,7 +9,8 @@
// except according to those terms.
const ARR: [usize; 1] = [2];
const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR unstable
const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR E0080
//~| unstable
fn main() {
}

View File

@ -8,30 +8,34 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
const X: usize = 42 && 39; //~ ERROR: can't do this op on integrals
const X: usize = 42 && 39; //~ ERROR E0080
//~| can't do this op on integrals
const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here
const X1: usize = 42 || 39; //~ ERROR: can't do this op on integrals
const X1: usize = 42 || 39; //~ ERROR E0080
//~| can't do this op on integrals
const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here
const X2: usize = -42 || -39; //~ ERROR: unary negation of unsigned integer
const X2: usize = -42 || -39; //~ ERROR E0080
//~| unary negation of unsigned integer
const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
const X3: usize = -42 && -39; //~ ERROR: unary negation of unsigned integer
const X3: usize = -42 && -39; //~ ERROR E0080
//~| unary negation of unsigned integer
const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
const Y: usize = 42.0 == 42.0;
const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length
const Y1: usize = 42.0 >= 42.0;
const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length
const Y2: usize = 42.0 <= 42.0;
const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length
const Y3: usize = 42.0 > 42.0;
const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length
const Y4: usize = 42.0 < 42.0;
const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length
const Y5: usize = 42.0 != 42.0;
const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length
fn main() {
let _ = ARR;

View File

@ -15,7 +15,8 @@
const ONE: usize = 1;
const TWO: usize = 2;
const LEN: usize = ONE - TWO;
//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
//~^ ERROR E0080
//~| attempted to subtract with overflow
fn main() {
let a: [i8; LEN] = unimplemented!();

View File

@ -16,5 +16,6 @@ const TWO: usize = 2;
fn main() {
let a: [i8; ONE - TWO] = unimplemented!();
//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
//~^ ERROR constant evaluation error [E0080]
//~| attempted to subtract with overflow
}

View File

@ -17,22 +17,26 @@ enum Cake {
use Cake::*;
const BOO: (Cake, Cake) = (Marmor, BlackForest);
//~^ ERROR: constant evaluation error: unimplemented constant expression: enum variants [E0471]
//~^ ERROR: constant evaluation error [E0080]
//~| unimplemented constant expression: enum variants
const FOO: Cake = BOO.1;
const fn foo() -> Cake {
Marmor //~ ERROR: constant evaluation error: unimplemented constant expression: enum variants
//~^ ERROR: unimplemented constant expression: enum variants
Marmor
//~^ ERROR: constant evaluation error [E0080]
//~| unimplemented constant expression: enum variants
//~^^^ ERROR: constant evaluation error [E0080]
//~| unimplemented constant expression: enum variants
}
const WORKS: Cake = Marmor;
const GOO: Cake = foo();
const GOO: Cake = foo(); //~ NOTE for expression here
fn main() {
match BlackForest {
FOO => println!("hi"), //~ NOTE: in pattern here
GOO => println!("meh"), //~ NOTE: in pattern here
FOO => println!("hi"), //~ NOTE: for pattern here
GOO => println!("meh"), //~ NOTE: for pattern here
WORKS => println!("möp"),
_ => println!("bye"),
}

View File

@ -10,7 +10,8 @@
const FOO: &'static[u32] = &[1, 2, 3];
const BAR: u32 = FOO[5];
//~^ ERROR index out of bounds: the len is 3 but the index is 5
//~^ ERROR constant evaluation error [E0080]
//~| index out of bounds: the len is 3 but the index is 5
fn main() {
let _ = BAR;

View File

@ -11,7 +11,8 @@
// Test spans of errors
const TUP: (usize,) = 5 << 64;
//~^ ERROR: attempted to shift left with overflow [E0250]
//~^ ERROR E0080
//~| attempted to shift left with overflow
const ARR: [i32; TUP.0] = [];
fn main() {

View File

@ -25,7 +25,8 @@ fn f_i8() {
Ok = i8::MAX - 1,
Ok2,
OhNo = 0_u8,
//~^ ERROR mismatched types
//~^ ERROR E0080
//~| mismatched types
}
let x = A::Ok;
@ -37,7 +38,8 @@ fn f_u8() {
Ok = u8::MAX - 1,
Ok2,
OhNo = 0_i8,
//~^ ERROR mismatched types
//~^ ERROR E0080
//~| mismatched types
}
let x = A::Ok;
@ -49,7 +51,8 @@ fn f_i16() {
Ok = i16::MAX - 1,
Ok2,
OhNo = 0_u16,
//~^ ERROR mismatched types
//~^ ERROR E0080
//~| mismatched types
}
let x = A::Ok;
@ -61,7 +64,8 @@ fn f_u16() {
Ok = u16::MAX - 1,
Ok2,
OhNo = 0_i16,
//~^ ERROR mismatched types
//~^ ERROR E0080
//~| mismatched types
}
let x = A::Ok;
@ -73,7 +77,8 @@ fn f_i32() {
Ok = i32::MAX - 1,
Ok2,
OhNo = 0_u32,
//~^ ERROR mismatched types
//~^ ERROR E0080
//~| mismatched types
}
let x = A::Ok;
@ -85,7 +90,8 @@ fn f_u32() {
Ok = u32::MAX - 1,
Ok2,
OhNo = 0_i32,
//~^ ERROR mismatched types
//~^ ERROR E0080
//~| mismatched types
}
let x = A::Ok;
@ -97,7 +103,8 @@ fn f_i64() {
Ok = i64::MAX - 1,
Ok2,
OhNo = 0_u64,
//~^ ERROR mismatched types
//~^ ERROR E0080
//~| mismatched types
}
let x = A::Ok;
@ -109,7 +116,8 @@ fn f_u64() {
Ok = u64::MAX - 1,
Ok2,
OhNo = 0_i64,
//~^ ERROR mismatched types
//~^ ERROR E0080
//~| mismatched types
}
let x = A::Ok;

View File

@ -13,28 +13,32 @@
enum Eu8 {
Au8 = 23,
Bu8 = 223,
Cu8 = -23, //~ ERROR unary negation of unsigned integer
Cu8 = -23, //~ ERROR E0080
//~| unary negation of unsigned integer
}
#[repr(u16)]
enum Eu16 {
Au16 = 23,
Bu16 = 55555,
Cu16 = -22333, //~ ERROR unary negation of unsigned integer
Cu16 = -22333, //~ ERROR E0080
//~| unary negation of unsigned integer
}
#[repr(u32)]
enum Eu32 {
Au32 = 23,
Bu32 = 3_000_000_000,
Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
Cu32 = -2_000_000_000, //~ ERROR E0080
//~| unary negation of unsigned integer
}
#[repr(u64)]
enum Eu64 {
Au32 = 23,
Bu32 = 3_000_000_000,
Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
Cu32 = -2_000_000_000, //~ ERROR E0080
//~| unary negation of unsigned integer
}
// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a

View File

@ -9,9 +9,11 @@
// except according to those terms.
enum test {
div_zero = 1/0, //~ERROR constant evaluation error: attempted to divide by zero
div_zero = 1/0, //~ ERROR E0080
//~| attempted to divide by zero
rem_zero = 1%0,
//~^ ERROR constant evaluation error: attempted to calculate the remainder with a divisor of zero
//~^ ERROR E0080
//~| attempted to calculate the remainder with a divisor of zero
}
fn main() {}

View File

@ -18,14 +18,17 @@ impl std::ops::Neg for S {
fn main() {
let a = -1;
//~^ ERROR unary negation of unsigned integer
//~^ ERROR E0080
//~| unary negation of unsigned integer
let _b : u8 = a; // for infering variable a to u8.
let _d = -1u8;
//~^ ERROR unary negation of unsigned integer
//~^ ERROR E0080
//~| unary negation of unsigned integer
for _ in -10..10u8 {}
//~^ ERROR unary negation of unsigned integer
//~^ ERROR E0080
//~| unary negation of unsigned integer
-S; // should not trigger the gate; issue 26840
}

View File

@ -10,5 +10,6 @@
fn main() {
fn f(a: [u8; u32::DOESNOTEXIST]) {}
//~^ ERROR unresolved path in constant expression
//~^ ERROR constant evaluation error
//~| unresolved path in constant expression
}

View File

@ -12,10 +12,12 @@ enum Delicious {
Pie = 0x1,
Apple = 0x2,
ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
//~^ ERROR constant evaluation error: unresolved path in constant expression
//~^ ERROR constant evaluation error
//~| unresolved path in constant expression
}
const FOO: [u32; u8::MIN as usize] = [];
//~^ ERROR array length constant evaluation error: unresolved path in constant expression
//~^ ERROR constant evaluation error
//~| unresolved path in constant expression
fn main() {}

View File

@ -10,7 +10,8 @@
pub enum SomeEnum {
B = SomeEnum::A,
//~^ ERROR constant evaluation error: unresolved path in constant expression
//~^ ERROR constant evaluation error
//~| unresolved path in constant expression
}
fn main() {}

View File

@ -17,6 +17,7 @@ impl S {
}
static STUFF: [u8; S::N] = [0; S::N];
//~^ ERROR array length constant evaluation error: unresolved path in constant expression
//~^ ERROR constant evaluation error
//~| unresolved path in constant expression
fn main() {}

View File

@ -16,5 +16,5 @@ fn main() {
//~| expected type `usize`
//~| found type `S`
//~| expected usize, found struct `S`
//~| ERROR expected positive integer for repeat count, found struct
//~| ERROR expected usize for repeat count, found struct
}

View File

@ -14,7 +14,8 @@ fn main() {
match i {
0...index => println!("winner"),
//~^ ERROR non-constant path in constant expression
//~^ ERROR constant evaluation error
//~| non-constant path in constant expression
_ => println!("hello"),
}
}

View File

@ -11,6 +11,6 @@
// Regression test for issue #28586
pub trait Foo {}
impl Foo for [u8; usize::BYTES] {} //~ ERROR E0250
impl Foo for [u8; usize::BYTES] {} //~ ERROR E0080
fn main() { }

View File

@ -15,7 +15,8 @@ fn main() {
enum Stuff {
Bar = foo
//~^ ERROR attempt to use a non-constant value in a constant
//~^^ ERROR constant evaluation error: non-constant path in constant expression
//~^^ ERROR constant evaluation error
//~| non-constant path in constant expression
}
println!("{}", Stuff::Bar);

View File

@ -10,13 +10,13 @@
enum Foo {
A = 1i64,
//~^ ERROR mismatched types:
//~| expected `isize`,
//~| found `i64` [E0080]
//~^ ERROR constant evaluation error
//~| expected `isize`
//~| found `i64`
B = 2u8
//~^ ERROR mismatched types:
//~| expected `isize`,
//~| found `u8` [E0080]
//~^ ERROR constant evaluation error
//~| expected `isize`
//~| found `u8`
}
fn main() {}

View File

@ -15,5 +15,6 @@ enum State { ST_NULL, ST_WHITESPACE }
fn main() {
[State::ST_NULL; (State::ST_WHITESPACE as usize)];
//~^ ERROR expected constant integer for repeat count, but unimplemented constant expression
//~^ ERROR constant evaluation error
//~| unimplemented constant expression: enum variants
}

View File

@ -13,6 +13,8 @@
fn main() {
fn bar(n: usize) {
let _x = [0; n];
//~^ ERROR expected constant integer for repeat count, found variable
//~^ ERROR constant evaluation error
//~| non-constant path in constant expression
//~| NOTE `n` is a variable
}
}

View File

@ -12,6 +12,7 @@ fn main() {
let x = 0;
match 1 {
0 ... x => {}
//~^ ERROR non-constant path in constant expression
//~^ ERROR constant evaluation error
//~| non-constant path in constant expression
};
}

View File

@ -13,37 +13,38 @@
fn main() {
let n = 1;
let a = [0; n];
//~^ ERROR expected constant integer for repeat count, found variable [E0307]
//~^ ERROR constant evaluation error
//~| non-constant path in constant expression
let b = [0; ()];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `()`
//~| expected usize, found ()
//~| ERROR expected positive integer for repeat count, found tuple [E0306]
//~| ERROR expected usize for repeat count, found tuple [E0306]
let c = [0; true];
//~^ ERROR mismatched types
//~| expected usize, found bool
//~| ERROR expected positive integer for repeat count, found boolean [E0306]
//~| ERROR expected usize for repeat count, found boolean [E0306]
let d = [0; 0.5];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `_`
//~| expected usize, found floating-point variable
//~| ERROR expected positive integer for repeat count, found float [E0306]
//~| ERROR expected usize for repeat count, found float [E0306]
let e = [0; "foo"];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `&'static str`
//~| expected usize, found &-ptr
//~| ERROR expected positive integer for repeat count, found string literal [E0306]
//~| ERROR expected usize for repeat count, found string literal [E0306]
let f = [0; -4_isize];
//~^ ERROR mismatched types
//~^ ERROR constant evaluation error
//~| expected `usize`
//~| found `isize`
//~| ERROR mismatched types:
//~| ERROR mismatched types
//~| expected usize, found isize
let f = [0_usize; -1_isize];
//~^ ERROR mismatched types
//~^ ERROR constant evaluation error
//~| expected `usize`
//~| found `isize`
//~| ERROR mismatched types
@ -56,5 +57,5 @@ fn main() {
//~| expected type `usize`
//~| found type `main::G`
//~| expected usize, found struct `main::G`
//~| ERROR expected positive integer for repeat count, found struct [E0306]
//~| ERROR expected usize for repeat count, found struct [E0306]
}