rustc_const_eval: always demand typeck_tables for evaluating constants.
This commit is contained in:
parent
c832e6f327
commit
e7a48821c0
60 changed files with 706 additions and 1222 deletions
|
@ -390,44 +390,6 @@ RFC. It is, however, [currently unimplemented][iss15872].
|
|||
[iss15872]: https://github.com/rust-lang/rust/issues/15872
|
||||
"##,
|
||||
|
||||
E0109: r##"
|
||||
You tried to give a type parameter to a type which doesn't need it. Erroneous
|
||||
code example:
|
||||
|
||||
```compile_fail,E0109
|
||||
type X = u32<i32>; // error: type parameters are not allowed on this type
|
||||
```
|
||||
|
||||
Please check that you used the correct type and recheck its definition. Perhaps
|
||||
it doesn't need the type parameter.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
type X = u32; // this compiles
|
||||
```
|
||||
|
||||
Note that type parameters for enum-variant constructors go after the variant,
|
||||
not after the enum (Option::None::<u32>, not Option::<u32>::None).
|
||||
"##,
|
||||
|
||||
E0110: r##"
|
||||
You tried to give a lifetime parameter to a type which doesn't need it.
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0110
|
||||
type X = u32<'static>; // error: lifetime parameters are not allowed on
|
||||
// this type
|
||||
```
|
||||
|
||||
Please check that the correct type was used and recheck its definition; perhaps
|
||||
it doesn't need the lifetime parameter. Example:
|
||||
|
||||
```
|
||||
type X = u32; // ok!
|
||||
```
|
||||
"##,
|
||||
|
||||
E0133: r##"
|
||||
Unsafe code was used outside of an unsafe function or block.
|
||||
|
||||
|
@ -627,41 +589,6 @@ attributes:
|
|||
See also https://doc.rust-lang.org/book/no-stdlib.html
|
||||
"##,
|
||||
|
||||
E0229: r##"
|
||||
An associated type binding was done outside of the type parameter declaration
|
||||
and `where` clause. Erroneous code example:
|
||||
|
||||
```compile_fail,E0229
|
||||
pub trait Foo {
|
||||
type A;
|
||||
fn boo(&self) -> <Self as Foo>::A;
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl Foo for isize {
|
||||
type A = usize;
|
||||
fn boo(&self) -> usize { 42 }
|
||||
}
|
||||
|
||||
fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
|
||||
// error: associated type bindings are not allowed here
|
||||
```
|
||||
|
||||
To solve this error, please move the type bindings in the type parameter
|
||||
declaration:
|
||||
|
||||
```ignore
|
||||
fn baz<I: Foo<A=Bar>>(x: &<I as Foo>::A) {} // ok!
|
||||
```
|
||||
|
||||
Or in the `where` clause:
|
||||
|
||||
```ignore
|
||||
fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0261: r##"
|
||||
When using a lifetime like `'a` in a type, it must be declared before being
|
||||
used.
|
||||
|
|
|
@ -76,7 +76,6 @@ pub mod infer;
|
|||
pub mod lint;
|
||||
|
||||
pub mod middle {
|
||||
pub mod astconv_util;
|
||||
pub mod expr_use_visitor;
|
||||
pub mod const_val;
|
||||
pub mod cstore;
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
// Copyright 2012-2014 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.
|
||||
|
||||
/*!
|
||||
* This module contains a simple utility routine
|
||||
* used by both `typeck` and `const_eval`.
|
||||
* Almost certainly this could (and should) be refactored out of existence.
|
||||
*/
|
||||
|
||||
use hir;
|
||||
use hir::def::Def;
|
||||
use ty::{Ty, TyCtxt};
|
||||
|
||||
use syntax_pos::Span;
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn prohibit_type_params(self, segments: &[hir::PathSegment]) {
|
||||
for segment in segments {
|
||||
for typ in segment.parameters.types() {
|
||||
struct_span_err!(self.sess, typ.span, E0109,
|
||||
"type parameters are not allowed on this type")
|
||||
.span_label(typ.span, &format!("type parameter not allowed"))
|
||||
.emit();
|
||||
break;
|
||||
}
|
||||
for lifetime in segment.parameters.lifetimes() {
|
||||
struct_span_err!(self.sess, lifetime.span, E0110,
|
||||
"lifetime parameters are not allowed on this type")
|
||||
.span_label(lifetime.span,
|
||||
&format!("lifetime parameter not allowed on this type"))
|
||||
.emit();
|
||||
break;
|
||||
}
|
||||
for binding in segment.parameters.bindings() {
|
||||
self.prohibit_projection(binding.span);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prohibit_projection(self, span: Span)
|
||||
{
|
||||
let mut err = struct_span_err!(self.sess, span, E0229,
|
||||
"associated type bindings are not allowed here");
|
||||
err.span_label(span, &format!("associate type not allowed here")).emit();
|
||||
}
|
||||
|
||||
pub fn prim_ty_to_ty(self,
|
||||
segments: &[hir::PathSegment],
|
||||
nty: hir::PrimTy)
|
||||
-> Ty<'tcx> {
|
||||
self.prohibit_type_params(segments);
|
||||
match nty {
|
||||
hir::TyBool => self.types.bool,
|
||||
hir::TyChar => self.types.char,
|
||||
hir::TyInt(it) => self.mk_mach_int(it),
|
||||
hir::TyUint(uit) => self.mk_mach_uint(uit),
|
||||
hir::TyFloat(ft) => self.mk_mach_float(ft),
|
||||
hir::TyStr => self.mk_str()
|
||||
}
|
||||
}
|
||||
|
||||
/// If a type in the AST is a primitive type, return the ty::Ty corresponding
|
||||
/// to it.
|
||||
pub fn ast_ty_to_prim_ty(self, ast_ty: &hir::Ty) -> Option<Ty<'tcx>> {
|
||||
if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = ast_ty.node {
|
||||
if let Def::PrimTy(nty) = path.def {
|
||||
Some(self.prim_ty_to_ty(&path.segments, nty))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,28 +12,30 @@ use syntax::symbol::InternedString;
|
|||
use syntax::ast;
|
||||
use std::rc::Rc;
|
||||
use hir::def_id::DefId;
|
||||
use ty::subst::Substs;
|
||||
use rustc_const_math::*;
|
||||
|
||||
use self::ConstVal::*;
|
||||
pub use rustc_const_math::ConstInt;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
|
||||
pub enum ConstVal {
|
||||
pub enum ConstVal<'tcx> {
|
||||
Float(ConstFloat),
|
||||
Integral(ConstInt),
|
||||
Str(InternedString),
|
||||
ByteStr(Rc<Vec<u8>>),
|
||||
Bool(bool),
|
||||
Function(DefId),
|
||||
Struct(BTreeMap<ast::Name, ConstVal>),
|
||||
Tuple(Vec<ConstVal>),
|
||||
Array(Vec<ConstVal>),
|
||||
Repeat(Box<ConstVal>, u64),
|
||||
Function(DefId, &'tcx Substs<'tcx>),
|
||||
Struct(BTreeMap<ast::Name, ConstVal<'tcx>>),
|
||||
Tuple(Vec<ConstVal<'tcx>>),
|
||||
Array(Vec<ConstVal<'tcx>>),
|
||||
Repeat(Box<ConstVal<'tcx>>, u64),
|
||||
Char(char),
|
||||
}
|
||||
|
||||
impl ConstVal {
|
||||
impl<'tcx> ConstVal<'tcx> {
|
||||
pub fn description(&self) -> &'static str {
|
||||
match *self {
|
||||
Float(f) => f.description(),
|
||||
|
@ -43,7 +45,7 @@ impl ConstVal {
|
|||
Bool(_) => "boolean",
|
||||
Struct(_) => "struct",
|
||||
Tuple(_) => "tuple",
|
||||
Function(_) => "function definition",
|
||||
Function(..) => "function definition",
|
||||
Array(..) => "array",
|
||||
Repeat(..) => "repeat",
|
||||
Char(..) => "char",
|
||||
|
@ -53,8 +55,7 @@ impl ConstVal {
|
|||
pub fn to_const_int(&self) -> Option<ConstInt> {
|
||||
match *self {
|
||||
ConstVal::Integral(i) => Some(i),
|
||||
ConstVal::Bool(true) => Some(ConstInt::Infer(1)),
|
||||
ConstVal::Bool(false) => Some(ConstInt::Infer(0)),
|
||||
ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)),
|
||||
ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)),
|
||||
_ => None
|
||||
}
|
||||
|
|
|
@ -542,7 +542,7 @@ impl<'tcx> Terminator<'tcx> {
|
|||
impl<'tcx> TerminatorKind<'tcx> {
|
||||
pub fn if_<'a, 'gcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>,
|
||||
t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
|
||||
static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::Infer(0)];
|
||||
static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)];
|
||||
TerminatorKind::SwitchInt {
|
||||
discr: cond,
|
||||
switch_ty: tcx.types.bool,
|
||||
|
@ -1224,7 +1224,7 @@ pub enum Literal<'tcx> {
|
|||
substs: &'tcx Substs<'tcx>,
|
||||
},
|
||||
Value {
|
||||
value: ConstVal,
|
||||
value: ConstVal<'tcx>,
|
||||
},
|
||||
Promoted {
|
||||
// Index into the `promoted` vector of `Mir`.
|
||||
|
@ -1271,7 +1271,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
|
|||
write!(fmt, "b\"{}\"", escaped)
|
||||
}
|
||||
Bool(b) => write!(fmt, "{:?}", b),
|
||||
Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
|
||||
Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
|
||||
Struct(_) | Tuple(_) | Array(_) | Repeat(..) =>
|
||||
bug!("ConstVal `{:?}` should not be in MIR", const_val),
|
||||
Char(c) => write!(fmt, "{:?}", c),
|
||||
|
|
|
@ -244,6 +244,10 @@ pub struct TypeckTables<'tcx> {
|
|||
/// Set of trait imports actually used in the method resolution.
|
||||
/// This is used for warning unused imports.
|
||||
pub used_trait_imports: DefIdSet,
|
||||
|
||||
/// If any errors occurred while type-checking this body,
|
||||
/// this field will be set to `true`.
|
||||
pub tainted_by_errors: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeckTables<'tcx> {
|
||||
|
@ -262,6 +266,7 @@ impl<'tcx> TypeckTables<'tcx> {
|
|||
cast_kinds: NodeMap(),
|
||||
lints: lint::LintTable::new(),
|
||||
used_trait_imports: DefIdSet(),
|
||||
tainted_by_errors: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions};
|
|||
use syntax::ast::{FloatTy, IntTy, UintTy};
|
||||
use syntax::attr;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
use rustc_const_math::ConstInt;
|
||||
|
||||
use std::cmp;
|
||||
use std::fmt;
|
||||
|
@ -1183,11 +1182,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
|||
i64::min_value(),
|
||||
true);
|
||||
for discr in def.discriminants(tcx) {
|
||||
let x = match discr.erase_type() {
|
||||
ConstInt::InferSigned(i) => i as i64,
|
||||
ConstInt::Infer(i) => i as u64 as i64,
|
||||
_ => bug!()
|
||||
};
|
||||
let x = discr.to_u128_unchecked() as i64;
|
||||
if x == 0 { non_zero = false; }
|
||||
if x < min { min = x; }
|
||||
if x > max { max = x; }
|
||||
|
|
|
@ -381,7 +381,7 @@ define_maps! { <'tcx>
|
|||
|
||||
/// Results of evaluating monomorphic constants embedded in
|
||||
/// other items, such as enum variant explicit discriminants.
|
||||
pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal, ()>
|
||||
pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal<'tcx>, ()>
|
||||
}
|
||||
|
||||
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
|
||||
|
|
|
@ -47,6 +47,35 @@ type Disr = ConstInt;
|
|||
}
|
||||
|
||||
|
||||
macro_rules! typed_literal {
|
||||
($tcx:expr, $ty:expr, $lit:expr) => {
|
||||
match $ty {
|
||||
SignedInt(ast::IntTy::I8) => ConstInt::I8($lit),
|
||||
SignedInt(ast::IntTy::I16) => ConstInt::I16($lit),
|
||||
SignedInt(ast::IntTy::I32) => ConstInt::I32($lit),
|
||||
SignedInt(ast::IntTy::I64) => ConstInt::I64($lit),
|
||||
SignedInt(ast::IntTy::I128) => ConstInt::I128($lit),
|
||||
SignedInt(ast::IntTy::Is) => match $tcx.sess.target.int_type {
|
||||
ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16($lit)),
|
||||
ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32($lit)),
|
||||
ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64($lit)),
|
||||
_ => bug!(),
|
||||
},
|
||||
UnsignedInt(ast::UintTy::U8) => ConstInt::U8($lit),
|
||||
UnsignedInt(ast::UintTy::U16) => ConstInt::U16($lit),
|
||||
UnsignedInt(ast::UintTy::U32) => ConstInt::U32($lit),
|
||||
UnsignedInt(ast::UintTy::U64) => ConstInt::U64($lit),
|
||||
UnsignedInt(ast::UintTy::U128) => ConstInt::U128($lit),
|
||||
UnsignedInt(ast::UintTy::Us) => match $tcx.sess.target.uint_type {
|
||||
ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16($lit)),
|
||||
ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32($lit)),
|
||||
ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64($lit)),
|
||||
_ => bug!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntTypeExt for attr::IntType {
|
||||
fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
|
||||
match *self {
|
||||
|
@ -66,30 +95,7 @@ impl IntTypeExt for attr::IntType {
|
|||
}
|
||||
|
||||
fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
|
||||
match *self {
|
||||
SignedInt(ast::IntTy::I8) => ConstInt::I8(0),
|
||||
SignedInt(ast::IntTy::I16) => ConstInt::I16(0),
|
||||
SignedInt(ast::IntTy::I32) => ConstInt::I32(0),
|
||||
SignedInt(ast::IntTy::I64) => ConstInt::I64(0),
|
||||
SignedInt(ast::IntTy::I128) => ConstInt::I128(0),
|
||||
SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type {
|
||||
ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16(0)),
|
||||
ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)),
|
||||
ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64(0)),
|
||||
_ => bug!(),
|
||||
},
|
||||
UnsignedInt(ast::UintTy::U8) => ConstInt::U8(0),
|
||||
UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0),
|
||||
UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0),
|
||||
UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0),
|
||||
UnsignedInt(ast::UintTy::U128) => ConstInt::U128(0),
|
||||
UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type {
|
||||
ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(0)),
|
||||
ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)),
|
||||
ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(0)),
|
||||
_ => bug!(),
|
||||
},
|
||||
}
|
||||
typed_literal!(tcx, *self, 0)
|
||||
}
|
||||
|
||||
fn assert_ty_matches(&self, val: Disr) {
|
||||
|
@ -114,7 +120,7 @@ impl IntTypeExt for attr::IntType {
|
|||
-> Option<Disr> {
|
||||
if let Some(val) = val {
|
||||
self.assert_ty_matches(val);
|
||||
(val + ConstInt::Infer(1)).ok()
|
||||
(val + typed_literal!(tcx, *self, 1)).ok()
|
||||
} else {
|
||||
Some(self.initial_discriminant(tcx))
|
||||
}
|
||||
|
|
|
@ -221,21 +221,21 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Constructor {
|
||||
pub enum Constructor<'tcx> {
|
||||
/// The constructor of all patterns that don't vary by constructor,
|
||||
/// e.g. struct patterns and fixed-length arrays.
|
||||
Single,
|
||||
/// Enum variants.
|
||||
Variant(DefId),
|
||||
/// Literal values.
|
||||
ConstantValue(ConstVal),
|
||||
ConstantValue(ConstVal<'tcx>),
|
||||
/// Ranges of literal values (`2...5` and `2..5`).
|
||||
ConstantRange(ConstVal, ConstVal, RangeEnd),
|
||||
ConstantRange(ConstVal<'tcx>, ConstVal<'tcx>, RangeEnd),
|
||||
/// Array patterns of length n.
|
||||
Slice(usize),
|
||||
}
|
||||
|
||||
impl<'tcx> Constructor {
|
||||
impl<'tcx> Constructor<'tcx> {
|
||||
fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> usize {
|
||||
match self {
|
||||
&Variant(vid) => adt.variant_index_with_id(vid),
|
||||
|
@ -289,7 +289,7 @@ impl<'tcx> Witness<'tcx> {
|
|||
fn push_wild_constructor<'a>(
|
||||
mut self,
|
||||
cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
ctor: &Constructor,
|
||||
ctor: &Constructor<'tcx>,
|
||||
ty: Ty<'tcx>)
|
||||
-> Self
|
||||
{
|
||||
|
@ -321,7 +321,7 @@ impl<'tcx> Witness<'tcx> {
|
|||
fn apply_constructor<'a>(
|
||||
mut self,
|
||||
cx: &MatchCheckCtxt<'a,'tcx>,
|
||||
ctor: &Constructor,
|
||||
ctor: &Constructor<'tcx>,
|
||||
ty: Ty<'tcx>)
|
||||
-> Self
|
||||
{
|
||||
|
@ -399,7 +399,8 @@ impl<'tcx> Witness<'tcx> {
|
|||
/// We make sure to omit constructors that are statically impossible. eg for
|
||||
/// Option<!> we do not include Some(_) in the returned list of constructors.
|
||||
fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
pcx: PatternContext<'tcx>) -> Vec<Constructor>
|
||||
pcx: PatternContext<'tcx>)
|
||||
-> Vec<Constructor<'tcx>>
|
||||
{
|
||||
debug!("all_constructors({:?})", pcx.ty);
|
||||
match pcx.ty.sty {
|
||||
|
@ -664,7 +665,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
|
|||
cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
&Matrix(ref m): &Matrix<'p, 'tcx>,
|
||||
v: &[&'p Pattern<'tcx>],
|
||||
ctor: Constructor,
|
||||
ctor: Constructor<'tcx>,
|
||||
lty: Ty<'tcx>,
|
||||
witness: WitnessPreference) -> Usefulness<'tcx>
|
||||
{
|
||||
|
@ -702,10 +703,10 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
|
|||
/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
|
||||
///
|
||||
/// Returns None in case of a catch-all, which can't be specialized.
|
||||
fn pat_constructors(_cx: &mut MatchCheckCtxt,
|
||||
pat: &Pattern,
|
||||
pcx: PatternContext)
|
||||
-> Option<Vec<Constructor>>
|
||||
fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
|
||||
pat: &Pattern<'tcx>,
|
||||
pcx: PatternContext)
|
||||
-> Option<Vec<Constructor<'tcx>>>
|
||||
{
|
||||
match *pat.kind {
|
||||
PatternKind::Binding { .. } | PatternKind::Wild =>
|
||||
|
|
|
@ -124,7 +124,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
|||
"statics cannot be referenced in patterns");
|
||||
}
|
||||
PatternError::ConstEval(err) => {
|
||||
report_const_eval_err(self.tcx, &err, pat_span, "pattern").emit();
|
||||
report_const_eval_err(self.tcx, &err, pat_span, "pattern");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -576,22 +576,6 @@ integer type:
|
|||
https://doc.rust-lang.org/reference.html#ffi-attributes
|
||||
"##,
|
||||
|
||||
|
||||
E0306: r##"
|
||||
In an array type `[T; N]`, `N` is the number of elements in the array. This
|
||||
must be an unsigned integer. Erroneous code example:
|
||||
|
||||
```compile_fail,E0306
|
||||
const X: [i32; true] = [0]; // error: expected `usize` for array length,
|
||||
// found boolean
|
||||
```
|
||||
|
||||
Working example:
|
||||
|
||||
```
|
||||
const X: [i32; 1] = [0];
|
||||
```
|
||||
"##,
|
||||
}
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -21,6 +21,7 @@
|
|||
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/")]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(rustc_private)]
|
||||
#![feature(staged_api)]
|
||||
|
|
|
@ -27,9 +27,9 @@ use syntax::ptr::P;
|
|||
use syntax_pos::Span;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PatternError {
|
||||
pub enum PatternError<'tcx> {
|
||||
StaticInPattern(Span),
|
||||
ConstEval(eval::ConstEvalErr),
|
||||
ConstEval(eval::ConstEvalErr<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -84,12 +84,12 @@ pub enum PatternKind<'tcx> {
|
|||
},
|
||||
|
||||
Constant {
|
||||
value: ConstVal,
|
||||
value: ConstVal<'tcx>,
|
||||
},
|
||||
|
||||
Range {
|
||||
lo: ConstVal,
|
||||
hi: ConstVal,
|
||||
lo: ConstVal<'tcx>,
|
||||
hi: ConstVal<'tcx>,
|
||||
end: RangeEnd,
|
||||
},
|
||||
|
||||
|
@ -118,7 +118,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
|
|||
ConstVal::Char(c) => write!(f, "{:?}", c),
|
||||
ConstVal::Struct(_) |
|
||||
ConstVal::Tuple(_) |
|
||||
ConstVal::Function(_) |
|
||||
ConstVal::Function(..) |
|
||||
ConstVal::Array(..) |
|
||||
ConstVal::Repeat(..) => bug!("{:?} not printable in a pattern", value)
|
||||
}
|
||||
|
@ -265,7 +265,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
|||
pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
pub tables: &'a ty::TypeckTables<'gcx>,
|
||||
pub errors: Vec<PatternError>,
|
||||
pub errors: Vec<PatternError<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
|
||||
|
@ -582,11 +582,11 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
|
|||
let tcx = self.tcx.global_tcx();
|
||||
let substs = self.tables.node_id_item_substs(id)
|
||||
.unwrap_or_else(|| tcx.intern_substs(&[]));
|
||||
match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
|
||||
Some((const_expr, const_tables, _const_ty)) => {
|
||||
match eval::lookup_const_by_id(tcx, def_id, substs) {
|
||||
Some((const_expr, const_tables)) => {
|
||||
// Enter the inlined constant's tables temporarily.
|
||||
let old_tables = self.tables;
|
||||
self.tables = const_tables.expect("missing tables after typeck");
|
||||
self.tables = const_tables;
|
||||
let pat = self.lower_const_expr(const_expr, pat_id, span);
|
||||
self.tables = old_tables;
|
||||
return pat;
|
||||
|
@ -609,7 +609,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
|
|||
|
||||
fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
|
||||
let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables);
|
||||
match const_cx.eval(expr, eval::EvalHint::ExprTypeChecked) {
|
||||
match const_cx.eval(expr) {
|
||||
Ok(value) => {
|
||||
PatternKind::Constant { value: value }
|
||||
}
|
||||
|
@ -796,7 +796,7 @@ macro_rules! CloneImpls {
|
|||
}
|
||||
|
||||
CloneImpls!{ <'tcx>
|
||||
Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal, Region,
|
||||
Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region,
|
||||
Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
|
||||
&'tcx Substs<'tcx>, &'tcx Kind<'tcx>
|
||||
}
|
||||
|
|
|
@ -17,13 +17,7 @@ use super::err::*;
|
|||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum ConstFloat {
|
||||
F32(f32),
|
||||
F64(f64),
|
||||
|
||||
// When the type isn't known, we have to operate on both possibilities.
|
||||
FInfer {
|
||||
f32: f32,
|
||||
f64: f64
|
||||
}
|
||||
F64(f64)
|
||||
}
|
||||
pub use self::ConstFloat::*;
|
||||
|
||||
|
@ -31,7 +25,6 @@ impl ConstFloat {
|
|||
/// Description of the type, not the value
|
||||
pub fn description(&self) -> &'static str {
|
||||
match *self {
|
||||
FInfer {..} => "float",
|
||||
F32(_) => "f32",
|
||||
F64(_) => "f64",
|
||||
}
|
||||
|
@ -41,17 +34,13 @@ impl ConstFloat {
|
|||
match *self {
|
||||
F32(f) => f.is_nan(),
|
||||
F64(f) => f.is_nan(),
|
||||
FInfer { f32, f64 } => f32.is_nan() || f64.is_nan()
|
||||
}
|
||||
}
|
||||
|
||||
/// Compares the values if they are of the same type
|
||||
pub fn try_cmp(self, rhs: Self) -> Result<Ordering, ConstMathErr> {
|
||||
match (self, rhs) {
|
||||
(F64(a), F64(b)) |
|
||||
(F64(a), FInfer { f64: b, .. }) |
|
||||
(FInfer { f64: a, .. }, F64(b)) |
|
||||
(FInfer { f64: a, .. }, FInfer { f64: b, .. }) => {
|
||||
(F64(a), F64(b)) => {
|
||||
// This is pretty bad but it is the existing behavior.
|
||||
Ok(if a == b {
|
||||
Ordering::Equal
|
||||
|
@ -62,9 +51,7 @@ impl ConstFloat {
|
|||
})
|
||||
}
|
||||
|
||||
(F32(a), F32(b)) |
|
||||
(F32(a), FInfer { f32: b, .. }) |
|
||||
(FInfer { f32: a, .. }, F32(b)) => {
|
||||
(F32(a), F32(b)) => {
|
||||
Ok(if a == b {
|
||||
Ordering::Equal
|
||||
} else if a < b {
|
||||
|
@ -86,10 +73,7 @@ impl ConstFloat {
|
|||
impl PartialEq for ConstFloat {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (*self, *other) {
|
||||
(F64(a), F64(b)) |
|
||||
(F64(a), FInfer { f64: b, .. }) |
|
||||
(FInfer { f64: a, .. }, F64(b)) |
|
||||
(FInfer { f64: a, .. }, FInfer { f64: b, .. }) => {
|
||||
(F64(a), F64(b)) => {
|
||||
unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)}
|
||||
}
|
||||
(F32(a), F32(b)) => {
|
||||
|
@ -105,7 +89,7 @@ impl Eq for ConstFloat {}
|
|||
impl hash::Hash for ConstFloat {
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
match *self {
|
||||
F64(a) | FInfer { f64: a, .. } => {
|
||||
F64(a) => {
|
||||
unsafe { transmute::<_,u64>(a) }.hash(state)
|
||||
}
|
||||
F32(a) => {
|
||||
|
@ -118,7 +102,6 @@ impl hash::Hash for ConstFloat {
|
|||
impl ::std::fmt::Display for ConstFloat {
|
||||
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
|
||||
match *self {
|
||||
FInfer { f64, .. } => write!(fmt, "{}", f64),
|
||||
F32(f) => write!(fmt, "{}f32", f),
|
||||
F64(f) => write!(fmt, "{}f64", f),
|
||||
}
|
||||
|
@ -131,20 +114,8 @@ macro_rules! derive_binop {
|
|||
type Output = Result<Self, ConstMathErr>;
|
||||
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
|
||||
match (self, rhs) {
|
||||
(F32(a), F32(b)) |
|
||||
(F32(a), FInfer { f32: b, .. }) |
|
||||
(FInfer { f32: a, .. }, F32(b)) => Ok(F32(a.$func(b))),
|
||||
|
||||
(F64(a), F64(b)) |
|
||||
(FInfer { f64: a, .. }, F64(b)) |
|
||||
(F64(a), FInfer { f64: b, .. }) => Ok(F64(a.$func(b))),
|
||||
|
||||
(FInfer { f32: a32, f64: a64 },
|
||||
FInfer { f32: b32, f64: b64 }) => Ok(FInfer {
|
||||
f32: a32.$func(b32),
|
||||
f64: a64.$func(b64)
|
||||
}),
|
||||
|
||||
(F32(a), F32(b)) => Ok(F32(a.$func(b))),
|
||||
(F64(a), F64(b)) => Ok(F64(a.$func(b))),
|
||||
_ => Err(UnequalTypes(Op::$op)),
|
||||
}
|
||||
}
|
||||
|
@ -164,10 +135,6 @@ impl ::std::ops::Neg for ConstFloat {
|
|||
match self {
|
||||
F32(f) => F32(-f),
|
||||
F64(f) => F64(-f),
|
||||
FInfer { f32, f64 } => FInfer {
|
||||
f32: -f32,
|
||||
f64: -f64
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,8 +30,6 @@ pub enum ConstInt {
|
|||
U64(u64),
|
||||
U128(u128),
|
||||
Usize(ConstUsize),
|
||||
Infer(u128),
|
||||
InferSigned(i128),
|
||||
}
|
||||
pub use self::ConstInt::*;
|
||||
|
||||
|
@ -92,7 +90,7 @@ impl ConstInt {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new unsigned ConstInt with matching type while also checking that overflow does
|
||||
/// Creates a new signed ConstInt with matching type while also checking that overflow does
|
||||
/// not happen.
|
||||
pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option<ConstInt> {
|
||||
match ty {
|
||||
|
@ -107,103 +105,33 @@ impl ConstInt {
|
|||
}
|
||||
}
|
||||
|
||||
/// If either value is `Infer` or `InferSigned`, try to turn the value into the type of
|
||||
/// the other value. If both values have no type, don't do anything
|
||||
pub fn infer(self, other: Self) -> Result<(Self, Self), ConstMathErr> {
|
||||
let inferred = match (self, other) {
|
||||
(InferSigned(_), InferSigned(_))
|
||||
| (Infer(_), Infer(_)) => self, // no inference possible
|
||||
// kindof wrong, you could have had values > I64MAX during computation of a
|
||||
(Infer(a @ 0...ubounds::I64MAX), InferSigned(_)) => InferSigned(a as i128),
|
||||
(Infer(_), InferSigned(_)) => return Err(ConstMathErr::NotInRange),
|
||||
(_, InferSigned(_))
|
||||
| (_, Infer(_)) => return other.infer(self).map(|(b, a)| (a, b)),
|
||||
|
||||
(Infer(a @ 0...ubounds::I8MAX), I8(_)) => I8(a as i64 as i8),
|
||||
(Infer(a @ 0...ubounds::I16MAX), I16(_)) => I16(a as i64 as i16),
|
||||
(Infer(a @ 0...ubounds::I32MAX), I32(_)) => I32(a as i64 as i32),
|
||||
(Infer(a @ 0...ubounds::I64MAX), I64(_)) => I64(a as i64),
|
||||
(Infer(a @ 0...ubounds::I128MAX), I128(_)) => I128(a as i128),
|
||||
(Infer(a @ 0...ubounds::I16MAX), Isize(Is16(_))) => Isize(Is16(a as i64 as i16)),
|
||||
(Infer(a @ 0...ubounds::I32MAX), Isize(Is32(_))) => Isize(Is32(a as i64 as i32)),
|
||||
(Infer(a @ 0...ubounds::I64MAX), Isize(Is64(_))) => Isize(Is64(a as i64)),
|
||||
(Infer(a @ 0...ubounds::U8MAX), U8(_)) => U8(a as u8),
|
||||
(Infer(a @ 0...ubounds::U16MAX), U16(_)) => U16(a as u16),
|
||||
(Infer(a @ 0...ubounds::U32MAX), U32(_)) => U32(a as u32),
|
||||
(Infer(a @ 0...ubounds::U64MAX), U64(_)) => U64(a as u64),
|
||||
(Infer(a @ 0...ubounds::U128MAX), U128(_)) => U128(a as u128),
|
||||
(Infer(a @ 0...ubounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)),
|
||||
(Infer(a @ 0...ubounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
|
||||
(Infer(a @ 0...ubounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
|
||||
|
||||
(Infer(_), _) => return Err(ConstMathErr::NotInRange),
|
||||
|
||||
(InferSigned(a @ ibounds::I8MIN...ibounds::I8MAX), I8(_)) => I8(a as i8),
|
||||
(InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), I16(_)) => I16(a as i16),
|
||||
(InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), I32(_)) => I32(a as i32),
|
||||
(InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), I64(_)) => I64(a as i64),
|
||||
(InferSigned(a @ ibounds::I128MIN...ibounds::I128MAX), I128(_)) => I128(a as i128),
|
||||
(InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), Isize(Is16(_))) => {
|
||||
Isize(Is16(a as i16))
|
||||
},
|
||||
(InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), Isize(Is32(_))) => {
|
||||
Isize(Is32(a as i32))
|
||||
},
|
||||
(InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), Isize(Is64(_))) => {
|
||||
Isize(Is64(a as i64))
|
||||
},
|
||||
(InferSigned(a @ 0...ibounds::U8MAX), U8(_)) => U8(a as u8),
|
||||
(InferSigned(a @ 0...ibounds::U16MAX), U16(_)) => U16(a as u16),
|
||||
(InferSigned(a @ 0...ibounds::U32MAX), U32(_)) => U32(a as u32),
|
||||
(InferSigned(a @ 0...ibounds::U64MAX), U64(_)) => U64(a as u64),
|
||||
(InferSigned(a @ 0...ibounds::I128MAX), U128(_)) => U128(a as u128),
|
||||
(InferSigned(a @ 0...ibounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)),
|
||||
(InferSigned(a @ 0...ibounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
|
||||
(InferSigned(a @ 0...ibounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
|
||||
(InferSigned(_), _) => return Err(ConstMathErr::NotInRange),
|
||||
_ => self, // already known types
|
||||
};
|
||||
Ok((inferred, other))
|
||||
/// Creates a new unsigned ConstInt with matching type.
|
||||
pub fn new_unsigned_truncating(val: u128, ty: UintTy, usize_ty: UintTy) -> ConstInt {
|
||||
match ty {
|
||||
UintTy::U8 => U8(val as u8),
|
||||
UintTy::U16 => U16(val as u16),
|
||||
UintTy::U32 => U32(val as u32),
|
||||
UintTy::U64 => U64(val as u64),
|
||||
UintTy::Us => Usize(ConstUsize::new_truncating(val, usize_ty)),
|
||||
UintTy::U128 => U128(val)
|
||||
}
|
||||
}
|
||||
|
||||
/// Turn this value into an `Infer` or an `InferSigned`
|
||||
pub fn erase_type(self) -> Self {
|
||||
match self {
|
||||
Infer(i) => Infer(i),
|
||||
InferSigned(i) if i < 0 => InferSigned(i),
|
||||
I8(i) if i < 0 => InferSigned(i as i128),
|
||||
I16(i) if i < 0 => InferSigned(i as i128),
|
||||
I32(i) if i < 0 => InferSigned(i as i128),
|
||||
I64(i) if i < 0 => InferSigned(i as i128),
|
||||
I128(i) if i < 0 => InferSigned(i as i128),
|
||||
Isize(Is16(i)) if i < 0 => InferSigned(i as i128),
|
||||
Isize(Is32(i)) if i < 0 => InferSigned(i as i128),
|
||||
Isize(Is64(i)) if i < 0 => InferSigned(i as i128),
|
||||
InferSigned(i) => Infer(i as u128),
|
||||
I8(i) => Infer(i as u128),
|
||||
I16(i) => Infer(i as u128),
|
||||
I32(i) => Infer(i as u128),
|
||||
I64(i) => Infer(i as u128),
|
||||
I128(i) => Infer(i as u128),
|
||||
Isize(Is16(i)) => Infer(i as u128),
|
||||
Isize(Is32(i)) => Infer(i as u128),
|
||||
Isize(Is64(i)) => Infer(i as u128),
|
||||
U8(i) => Infer(i as u128),
|
||||
U16(i) => Infer(i as u128),
|
||||
U32(i) => Infer(i as u128),
|
||||
U64(i) => Infer(i as u128),
|
||||
U128(i) => Infer(i as u128),
|
||||
Usize(Us16(i)) => Infer(i as u128),
|
||||
Usize(Us32(i)) => Infer(i as u128),
|
||||
Usize(Us64(i)) => Infer(i as u128),
|
||||
/// Creates a new signed ConstInt with matching type.
|
||||
pub fn new_signed_truncating(val: i128, ty: IntTy, isize_ty: IntTy) -> ConstInt {
|
||||
match ty {
|
||||
IntTy::I8 => I8(val as i8),
|
||||
IntTy::I16 => I16(val as i16),
|
||||
IntTy::I32 => I32(val as i32),
|
||||
IntTy::I64 => I64(val as i64),
|
||||
IntTy::Is => Isize(ConstIsize::new_truncating(val, isize_ty)),
|
||||
IntTy::I128 => I128(val)
|
||||
}
|
||||
}
|
||||
|
||||
/// Description of the type, not the value
|
||||
pub fn description(&self) -> &'static str {
|
||||
match *self {
|
||||
Infer(_) => "not yet inferred integral",
|
||||
InferSigned(_) => "not yet inferred signed integral",
|
||||
I8(_) => "i8",
|
||||
I16(_) => "i16",
|
||||
I32(_) => "i32",
|
||||
|
@ -222,10 +150,23 @@ impl ConstInt {
|
|||
/// Erases the type and returns a u128.
|
||||
/// This is not the same as `-5i8 as u128` but as `-5i8 as i128 as u128`
|
||||
pub fn to_u128_unchecked(self) -> u128 {
|
||||
match self.erase_type() {
|
||||
ConstInt::Infer(i) => i,
|
||||
ConstInt::InferSigned(i) => i as u128,
|
||||
_ => unreachable!(),
|
||||
match self {
|
||||
I8(i) => i as i128 as u128,
|
||||
I16(i) => i as i128 as u128,
|
||||
I32(i) => i as i128 as u128,
|
||||
I64(i) => i as i128 as u128,
|
||||
I128(i) => i as i128 as u128,
|
||||
Isize(Is16(i)) => i as i128 as u128,
|
||||
Isize(Is32(i)) => i as i128 as u128,
|
||||
Isize(Is64(i)) => i as i128 as u128,
|
||||
U8(i) => i as u128,
|
||||
U16(i) => i as u128,
|
||||
U32(i) => i as u128,
|
||||
U64(i) => i as u128,
|
||||
U128(i) => i as u128,
|
||||
Usize(Us16(i)) => i as u128,
|
||||
Usize(Us32(i)) => i as u128,
|
||||
Usize(Us64(i)) => i as u128,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,8 +191,6 @@ impl ConstInt {
|
|||
/// Converts the value to a `u128` if it's in the range 0...std::u128::MAX
|
||||
pub fn to_u128(&self) -> Option<u128> {
|
||||
match *self {
|
||||
Infer(v) => Some(v),
|
||||
InferSigned(v) if v >= 0 => Some(v as u128),
|
||||
I8(v) if v >= 0 => Some(v as u128),
|
||||
I16(v) if v >= 0 => Some(v as u128),
|
||||
I32(v) if v >= 0 => Some(v as u128),
|
||||
|
@ -272,6 +211,48 @@ impl ConstInt {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_f32(self) -> f32 {
|
||||
match self {
|
||||
I8(i) => i as f32,
|
||||
I16(i) => i as f32,
|
||||
I32(i) => i as f32,
|
||||
I64(i) => i as f32,
|
||||
I128(i) => i as f32,
|
||||
Isize(Is16(i)) => i as f32,
|
||||
Isize(Is32(i)) => i as f32,
|
||||
Isize(Is64(i)) => i as f32,
|
||||
U8(i) => i as f32,
|
||||
U16(i) => i as f32,
|
||||
U32(i) => i as f32,
|
||||
U64(i) => i as f32,
|
||||
U128(i) => i as f32,
|
||||
Usize(Us16(i)) => i as f32,
|
||||
Usize(Us32(i)) => i as f32,
|
||||
Usize(Us64(i)) => i as f32,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_f64(self) -> f64 {
|
||||
match self {
|
||||
I8(i) => i as f64,
|
||||
I16(i) => i as f64,
|
||||
I32(i) => i as f64,
|
||||
I64(i) => i as f64,
|
||||
I128(i) => i as f64,
|
||||
Isize(Is16(i)) => i as f64,
|
||||
Isize(Is32(i)) => i as f64,
|
||||
Isize(Is64(i)) => i as f64,
|
||||
U8(i) => i as f64,
|
||||
U16(i) => i as f64,
|
||||
U32(i) => i as f64,
|
||||
U64(i) => i as f64,
|
||||
U128(i) => i as f64,
|
||||
Usize(Us16(i)) => i as f64,
|
||||
Usize(Us32(i)) => i as f64,
|
||||
Usize(Us64(i)) => i as f64,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_negative(&self) -> bool {
|
||||
match *self {
|
||||
I8(v) => v < 0,
|
||||
|
@ -282,14 +263,13 @@ impl ConstInt {
|
|||
Isize(Is16(v)) => v < 0,
|
||||
Isize(Is32(v)) => v < 0,
|
||||
Isize(Is64(v)) => v < 0,
|
||||
InferSigned(v) => v < 0,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Compares the values if they are of the same type
|
||||
pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> {
|
||||
match self.infer(rhs)? {
|
||||
match (self, rhs) {
|
||||
(I8(a), I8(b)) => Ok(a.cmp(&b)),
|
||||
(I16(a), I16(b)) => Ok(a.cmp(&b)),
|
||||
(I32(a), I32(b)) => Ok(a.cmp(&b)),
|
||||
|
@ -306,8 +286,6 @@ impl ConstInt {
|
|||
(Usize(Us16(a)), Usize(Us16(b))) => Ok(a.cmp(&b)),
|
||||
(Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)),
|
||||
(Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)),
|
||||
(Infer(a), Infer(b)) => Ok(a.cmp(&b)),
|
||||
(InferSigned(a), InferSigned(b)) => Ok(a.cmp(&b)),
|
||||
_ => Err(CmpBetweenUnequalTypes),
|
||||
}
|
||||
}
|
||||
|
@ -334,25 +312,23 @@ impl ConstInt {
|
|||
ConstInt::Usize(ConstUsize::Us16(i)) => ConstInt::Usize(ConstUsize::Us16(add1!(i))),
|
||||
ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))),
|
||||
ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))),
|
||||
ConstInt::Infer(_) | ConstInt::InferSigned(_) => panic!("no type info for const int"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn int_type(self) -> Option<IntType> {
|
||||
pub fn int_type(self) -> IntType {
|
||||
match self {
|
||||
ConstInt::I8(_) => Some(IntType::SignedInt(IntTy::I8)),
|
||||
ConstInt::I16(_) => Some(IntType::SignedInt(IntTy::I16)),
|
||||
ConstInt::I32(_) => Some(IntType::SignedInt(IntTy::I32)),
|
||||
ConstInt::I64(_) => Some(IntType::SignedInt(IntTy::I64)),
|
||||
ConstInt::I128(_) => Some(IntType::SignedInt(IntTy::I128)),
|
||||
ConstInt::Isize(_) => Some(IntType::SignedInt(IntTy::Is)),
|
||||
ConstInt::U8(_) => Some(IntType::UnsignedInt(UintTy::U8)),
|
||||
ConstInt::U16(_) => Some(IntType::UnsignedInt(UintTy::U16)),
|
||||
ConstInt::U32(_) => Some(IntType::UnsignedInt(UintTy::U32)),
|
||||
ConstInt::U64(_) => Some(IntType::UnsignedInt(UintTy::U64)),
|
||||
ConstInt::U128(_) => Some(IntType::UnsignedInt(UintTy::U128)),
|
||||
ConstInt::Usize(_) => Some(IntType::UnsignedInt(UintTy::Us)),
|
||||
_ => None,
|
||||
ConstInt::I8(_) => IntType::SignedInt(IntTy::I8),
|
||||
ConstInt::I16(_) => IntType::SignedInt(IntTy::I16),
|
||||
ConstInt::I32(_) => IntType::SignedInt(IntTy::I32),
|
||||
ConstInt::I64(_) => IntType::SignedInt(IntTy::I64),
|
||||
ConstInt::I128(_) => IntType::SignedInt(IntTy::I128),
|
||||
ConstInt::Isize(_) => IntType::SignedInt(IntTy::Is),
|
||||
ConstInt::U8(_) => IntType::UnsignedInt(UintTy::U8),
|
||||
ConstInt::U16(_) => IntType::UnsignedInt(UintTy::U16),
|
||||
ConstInt::U32(_) => IntType::UnsignedInt(UintTy::U32),
|
||||
ConstInt::U64(_) => IntType::UnsignedInt(UintTy::U64),
|
||||
ConstInt::U128(_) => IntType::UnsignedInt(UintTy::U128),
|
||||
ConstInt::Usize(_) => IntType::UnsignedInt(UintTy::Us),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -372,8 +348,6 @@ impl ::std::cmp::Ord for ConstInt {
|
|||
impl ::std::fmt::Display for ConstInt {
|
||||
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
|
||||
match *self {
|
||||
Infer(i) => write!(fmt, "{}", i),
|
||||
InferSigned(i) => write!(fmt, "{}", i),
|
||||
I8(i) => write!(fmt, "{}i8", i),
|
||||
I16(i) => write!(fmt, "{}i16", i),
|
||||
I32(i) => write!(fmt, "{}i32", i),
|
||||
|
@ -409,7 +383,7 @@ macro_rules! impl_binop {
|
|||
impl ::std::ops::$op for ConstInt {
|
||||
type Output = Result<Self, ConstMathErr>;
|
||||
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
|
||||
match self.infer(rhs)? {
|
||||
match (self, rhs) {
|
||||
(I8(a), I8(b)) => a.$checked_func(b).map(I8),
|
||||
(I16(a), I16(b)) => a.$checked_func(b).map(I16),
|
||||
(I32(a), I32(b)) => a.$checked_func(b).map(I32),
|
||||
|
@ -426,8 +400,6 @@ macro_rules! impl_binop {
|
|||
(Usize(Us16(a)), Usize(Us16(b))) => a.$checked_func(b).map(Us16).map(Usize),
|
||||
(Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize),
|
||||
(Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize),
|
||||
(Infer(a), Infer(b)) => a.$checked_func(b).map(Infer),
|
||||
(InferSigned(a), InferSigned(b)) => a.$checked_func(b).map(InferSigned),
|
||||
_ => return Err(UnequalTypes(Op::$op)),
|
||||
}.ok_or(Overflow(Op::$op))
|
||||
}
|
||||
|
@ -440,7 +412,7 @@ macro_rules! derive_binop {
|
|||
impl ::std::ops::$op for ConstInt {
|
||||
type Output = Result<Self, ConstMathErr>;
|
||||
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
|
||||
match self.infer(rhs)? {
|
||||
match (self, rhs) {
|
||||
(I8(a), I8(b)) => Ok(I8(a.$func(b))),
|
||||
(I16(a), I16(b)) => Ok(I16(a.$func(b))),
|
||||
(I32(a), I32(b)) => Ok(I32(a.$func(b))),
|
||||
|
@ -457,8 +429,6 @@ macro_rules! derive_binop {
|
|||
(Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a.$func(b)))),
|
||||
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))),
|
||||
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))),
|
||||
(Infer(a), Infer(b)) => Ok(Infer(a.$func(b))),
|
||||
(InferSigned(a), InferSigned(b)) => Ok(InferSigned(a.$func(b))),
|
||||
_ => Err(UnequalTypes(Op::$op)),
|
||||
}
|
||||
}
|
||||
|
@ -490,7 +460,6 @@ fn check_division(
|
|||
(Isize(_), Isize(Is16(0))) => Err(zerr),
|
||||
(Isize(_), Isize(Is32(0))) => Err(zerr),
|
||||
(Isize(_), Isize(Is64(0))) => Err(zerr),
|
||||
(InferSigned(_), InferSigned(0)) => Err(zerr),
|
||||
|
||||
(U8(_), U8(0)) => Err(zerr),
|
||||
(U16(_), U16(0)) => Err(zerr),
|
||||
|
@ -500,7 +469,6 @@ fn check_division(
|
|||
(Usize(_), Usize(Us16(0))) => Err(zerr),
|
||||
(Usize(_), Usize(Us32(0))) => Err(zerr),
|
||||
(Usize(_), Usize(Us64(0))) => Err(zerr),
|
||||
(Infer(_), Infer(0)) => Err(zerr),
|
||||
|
||||
(I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)),
|
||||
(I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)),
|
||||
|
@ -510,7 +478,6 @@ fn check_division(
|
|||
(Isize(Is16(::std::i16::MIN)), Isize(Is16(-1))) => Err(Overflow(op)),
|
||||
(Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)),
|
||||
(Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)),
|
||||
(InferSigned(I128_MIN), InferSigned(-1)) => Err(Overflow(op)),
|
||||
|
||||
_ => Ok(()),
|
||||
}
|
||||
|
@ -519,7 +486,7 @@ fn check_division(
|
|||
impl ::std::ops::Div for ConstInt {
|
||||
type Output = Result<Self, ConstMathErr>;
|
||||
fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
|
||||
let (lhs, rhs) = self.infer(rhs)?;
|
||||
let (lhs, rhs) = (self, rhs);
|
||||
check_division(lhs, rhs, Op::Div, DivisionByZero)?;
|
||||
match (lhs, rhs) {
|
||||
(I8(a), I8(b)) => Ok(I8(a/b)),
|
||||
|
@ -530,7 +497,6 @@ impl ::std::ops::Div for ConstInt {
|
|||
(Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a/b))),
|
||||
(Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))),
|
||||
(Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))),
|
||||
(InferSigned(a), InferSigned(b)) => Ok(InferSigned(a/b)),
|
||||
|
||||
(U8(a), U8(b)) => Ok(U8(a/b)),
|
||||
(U16(a), U16(b)) => Ok(U16(a/b)),
|
||||
|
@ -540,7 +506,6 @@ impl ::std::ops::Div for ConstInt {
|
|||
(Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a/b))),
|
||||
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))),
|
||||
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))),
|
||||
(Infer(a), Infer(b)) => Ok(Infer(a/b)),
|
||||
|
||||
_ => Err(UnequalTypes(Op::Div)),
|
||||
}
|
||||
|
@ -550,7 +515,7 @@ impl ::std::ops::Div for ConstInt {
|
|||
impl ::std::ops::Rem for ConstInt {
|
||||
type Output = Result<Self, ConstMathErr>;
|
||||
fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
|
||||
let (lhs, rhs) = self.infer(rhs)?;
|
||||
let (lhs, rhs) = (self, rhs);
|
||||
// should INT_MIN%-1 be zero or an error?
|
||||
check_division(lhs, rhs, Op::Rem, RemainderByZero)?;
|
||||
match (lhs, rhs) {
|
||||
|
@ -562,7 +527,6 @@ impl ::std::ops::Rem for ConstInt {
|
|||
(Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a%b))),
|
||||
(Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))),
|
||||
(Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))),
|
||||
(InferSigned(a), InferSigned(b)) => Ok(InferSigned(a%b)),
|
||||
|
||||
(U8(a), U8(b)) => Ok(U8(a%b)),
|
||||
(U16(a), U16(b)) => Ok(U16(a%b)),
|
||||
|
@ -572,7 +536,6 @@ impl ::std::ops::Rem for ConstInt {
|
|||
(Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a%b))),
|
||||
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))),
|
||||
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))),
|
||||
(Infer(a), Infer(b)) => Ok(Infer(a%b)),
|
||||
|
||||
_ => Err(UnequalTypes(Op::Rem)),
|
||||
}
|
||||
|
@ -600,8 +563,6 @@ impl ::std::ops::Shl<ConstInt> for ConstInt {
|
|||
Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shl(b), Op::Shl)))),
|
||||
Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
|
||||
Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
|
||||
Infer(a) => Ok(Infer(overflowing!(a.overflowing_shl(b), Op::Shl))),
|
||||
InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shl(b), Op::Shl))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -627,8 +588,6 @@ impl ::std::ops::Shr<ConstInt> for ConstInt {
|
|||
Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shr(b), Op::Shr)))),
|
||||
Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
|
||||
Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
|
||||
Infer(a) => Ok(Infer(overflowing!(a.overflowing_shr(b), Op::Shr))),
|
||||
InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shr(b), Op::Shr))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -648,9 +607,6 @@ impl ::std::ops::Neg for ConstInt {
|
|||
a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) |
|
||||
a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a),
|
||||
U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation),
|
||||
Infer(a @ 0...ubounds::I128MAX) => Ok(InferSigned(-(a as i128))),
|
||||
Infer(_) => Err(Overflow(Op::Neg)),
|
||||
InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -675,8 +631,6 @@ impl ::std::ops::Not for ConstInt {
|
|||
Usize(Us16(a)) => Ok(Usize(Us16(!a))),
|
||||
Usize(Us32(a)) => Ok(Usize(Us32(!a))),
|
||||
Usize(Us64(a)) => Ok(Usize(Us64(!a))),
|
||||
Infer(a) => Ok(Infer(!a)),
|
||||
InferSigned(a) => Ok(InferSigned(!a)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/")]
|
||||
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(rustc_private)]
|
||||
#![feature(staged_api)]
|
||||
|
|
|
@ -17,7 +17,6 @@ use rustc::ty::layout::{Layout, Primitive};
|
|||
use rustc::traits::Reveal;
|
||||
use middle::const_val::ConstVal;
|
||||
use rustc_const_eval::ConstContext;
|
||||
use rustc_const_eval::EvalHint::ExprTypeChecked;
|
||||
use util::nodemap::FxHashSet;
|
||||
use lint::{LateContext, LintContext, LintArray};
|
||||
use lint::{LintPass, LateLintPass};
|
||||
|
@ -109,7 +108,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
|||
}
|
||||
} else {
|
||||
let const_cx = ConstContext::with_tables(cx.tcx, cx.tables);
|
||||
match const_cx.eval(&r, ExprTypeChecked) {
|
||||
match const_cx.eval(&r) {
|
||||
Ok(ConstVal::Integral(i)) => {
|
||||
i.is_negative() ||
|
||||
i.to_u64()
|
||||
|
|
|
@ -230,9 +230,9 @@ pub enum EntryKind<'tcx> {
|
|||
Type,
|
||||
Enum(ReprOptions),
|
||||
Field,
|
||||
Variant(Lazy<VariantData>),
|
||||
Struct(Lazy<VariantData>, ReprOptions),
|
||||
Union(Lazy<VariantData>, ReprOptions),
|
||||
Variant(Lazy<VariantData<'tcx>>),
|
||||
Struct(Lazy<VariantData<'tcx>>, ReprOptions),
|
||||
Union(Lazy<VariantData<'tcx>>, ReprOptions),
|
||||
Fn(Lazy<FnData>),
|
||||
ForeignFn(Lazy<FnData>),
|
||||
Mod(Lazy<ModData>),
|
||||
|
@ -263,10 +263,10 @@ pub struct FnData {
|
|||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct VariantData {
|
||||
pub struct VariantData<'tcx> {
|
||||
pub ctor_kind: CtorKind,
|
||||
pub discr: ty::VariantDiscr,
|
||||
pub evaluated_discr: Option<ConstVal>,
|
||||
pub evaluated_discr: Option<ConstVal<'tcx>>,
|
||||
|
||||
/// If this is a struct's only variant, this
|
||||
/// is the index of the "struct ctor" item.
|
||||
|
|
|
@ -309,13 +309,13 @@ enum TestKind<'tcx> {
|
|||
// test the branches of enum
|
||||
SwitchInt {
|
||||
switch_ty: Ty<'tcx>,
|
||||
options: Vec<ConstVal>,
|
||||
indices: FxHashMap<ConstVal, usize>,
|
||||
options: Vec<ConstVal<'tcx>>,
|
||||
indices: FxHashMap<ConstVal<'tcx>, usize>,
|
||||
},
|
||||
|
||||
// test for equality
|
||||
Eq {
|
||||
value: ConstVal,
|
||||
value: ConstVal<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
},
|
||||
|
||||
|
|
|
@ -112,8 +112,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
test_lvalue: &Lvalue<'tcx>,
|
||||
candidate: &Candidate<'pat, 'tcx>,
|
||||
switch_ty: Ty<'tcx>,
|
||||
options: &mut Vec<ConstVal>,
|
||||
indices: &mut FxHashMap<ConstVal, usize>)
|
||||
options: &mut Vec<ConstVal<'tcx>>,
|
||||
indices: &mut FxHashMap<ConstVal<'tcx>, usize>)
|
||||
-> bool
|
||||
{
|
||||
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
|
||||
|
|
|
@ -223,6 +223,17 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
|
|||
builder.finish(vec![], ty)
|
||||
}
|
||||
|
||||
pub fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
|
||||
body_id: hir::BodyId)
|
||||
-> Mir<'tcx> {
|
||||
let span = hir.tcx().hir.span(hir.tcx().hir.body_owner(body_id));
|
||||
let ty = hir.tcx().types.err;
|
||||
let mut builder = Builder::new(hir, span, 0, ty);
|
||||
let source_info = builder.source_info(span);
|
||||
builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
|
||||
builder.finish(vec![], ty)
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
fn new(hir: Cx<'a, 'gcx, 'tcx>,
|
||||
span: Span,
|
||||
|
|
|
@ -17,7 +17,7 @@ use hair::cx::to_ref::ToRef;
|
|||
use rustc::hir::map;
|
||||
use rustc::hir::def::{Def, CtorKind};
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err};
|
||||
use rustc_const_eval::{ConstContext, fatal_const_eval_err};
|
||||
use rustc::ty::{self, AdtKind, VariantDef, Ty};
|
||||
use rustc::ty::cast::CastKind as TyCastKind;
|
||||
use rustc::hir;
|
||||
|
@ -594,7 +594,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
hir::ExprRepeat(ref v, count) => {
|
||||
let tcx = cx.tcx.global_tcx();
|
||||
let c = &cx.tcx.hir.body(count).value;
|
||||
let count = match ConstContext::new(tcx, count).eval(c, EvalHint::ExprTypeChecked) {
|
||||
let count = match ConstContext::new(tcx, count).eval(c) {
|
||||
Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
|
||||
Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
|
||||
Err(s) => fatal_const_eval_err(tcx, &s, c.span, "expression")
|
||||
|
|
|
@ -18,7 +18,7 @@ use hair::*;
|
|||
use rustc::mir::transform::MirSource;
|
||||
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err};
|
||||
use rustc_const_eval::{ConstContext, fatal_const_eval_err};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::map::blocks::FnLikeNode;
|
||||
|
@ -113,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
|||
|
||||
pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
|
||||
let tcx = self.tcx.global_tcx();
|
||||
match ConstContext::with_tables(tcx, self.tables()).eval(e, EvalHint::ExprTypeChecked) {
|
||||
match ConstContext::with_tables(tcx, self.tables()).eval(e) {
|
||||
Ok(value) => Literal::Value { value: value },
|
||||
Err(s) => fatal_const_eval_err(tcx, &s, e.span, "expression")
|
||||
}
|
||||
|
|
|
@ -98,7 +98,9 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
|
|||
let src = MirSource::from_node(tcx, id);
|
||||
tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
|
||||
let cx = Cx::new(&infcx, src);
|
||||
let mut mir = if let MirSource::Fn(id) = src {
|
||||
let mut mir = if cx.tables().tainted_by_errors {
|
||||
build::construct_error(cx, body_id)
|
||||
} else if let MirSource::Fn(id) = src {
|
||||
// fetch the fully liberated fn signature (that is, all bound
|
||||
// types/lifetimes replaced)
|
||||
let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
|
||||
|
|
|
@ -28,9 +28,8 @@ use rustc::dep_graph::DepNode;
|
|||
use rustc::ty::cast::CastKind;
|
||||
use rustc_const_eval::{ConstEvalErr, ConstContext};
|
||||
use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
|
||||
use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath, BadType};
|
||||
use rustc_const_eval::ErrKind::UnresolvedPath;
|
||||
use rustc_const_eval::EvalHint::ExprTypeChecked;
|
||||
use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
|
||||
use rustc_const_eval::ErrKind::{TypeckError};
|
||||
use rustc_const_math::{ConstMathErr, Op};
|
||||
use rustc::hir::def::{Def, CtorKind};
|
||||
use rustc::hir::def_id::DefId;
|
||||
|
@ -66,12 +65,12 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> {
|
|||
impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
|
||||
fn check_const_eval(&self, expr: &'gcx hir::Expr) {
|
||||
let const_cx = ConstContext::with_tables(self.tcx, self.tables);
|
||||
if let Err(err) = const_cx.eval(expr, ExprTypeChecked) {
|
||||
if let Err(err) = const_cx.eval(expr) {
|
||||
match err.kind {
|
||||
UnimplementedConstVal(_) => {}
|
||||
IndexOpFeatureGated => {}
|
||||
ErroneousReferencedConstant(_) => {}
|
||||
BadType(_) => {}
|
||||
TypeckError => {}
|
||||
_ => {
|
||||
self.tcx.sess.add_lint(CONST_ERR,
|
||||
expr.id,
|
||||
|
@ -240,18 +239,17 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
|
|||
|
||||
if self.in_fn && self.promotable {
|
||||
let const_cx = ConstContext::with_tables(self.tcx, self.tables);
|
||||
match const_cx.eval(ex, ExprTypeChecked) {
|
||||
match const_cx.eval(ex) {
|
||||
Ok(_) => {}
|
||||
Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
|
||||
Err(ConstEvalErr { kind: MiscCatchAll, .. }) |
|
||||
Err(ConstEvalErr { kind: MiscBinaryOp, .. }) |
|
||||
Err(ConstEvalErr { kind: NonConstPath, .. }) |
|
||||
Err(ConstEvalErr { kind: UnresolvedPath, .. }) |
|
||||
Err(ConstEvalErr { kind: ErroneousReferencedConstant(_), .. }) |
|
||||
Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), .. }) |
|
||||
Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), .. }) |
|
||||
Err(ConstEvalErr { kind: IndexOpFeatureGated, .. }) => {}
|
||||
Err(ConstEvalErr { kind: BadType(_), .. }) => {}
|
||||
Err(ConstEvalErr { kind: TypeckError, .. }) => {}
|
||||
Err(msg) => {
|
||||
self.tcx.sess.add_lint(CONST_ERR,
|
||||
ex.id,
|
||||
|
|
|
@ -213,11 +213,11 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
|
|||
g
|
||||
}
|
||||
|
||||
pub fn trans_static(ccx: &CrateContext,
|
||||
m: hir::Mutability,
|
||||
id: ast::NodeId,
|
||||
attrs: &[ast::Attribute])
|
||||
-> Result<ValueRef, ConstEvalErr> {
|
||||
pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
m: hir::Mutability,
|
||||
id: ast::NodeId,
|
||||
attrs: &[ast::Attribute])
|
||||
-> Result<ValueRef, ConstEvalErr<'tcx>> {
|
||||
unsafe {
|
||||
let def_id = ccx.tcx().hir.local_def_id(id);
|
||||
let g = get_static(ccx, def_id);
|
||||
|
|
|
@ -139,7 +139,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
if switch_ty == bcx.tcx().types.bool {
|
||||
let lltrue = llblock(self, targets[0]);
|
||||
let llfalse = llblock(self, targets[1]);
|
||||
if let [ConstInt::Infer(0)] = values[..] {
|
||||
if let [ConstInt::U8(0)] = values[..] {
|
||||
bcx.cond_br(discr.immediate(), llfalse, lltrue);
|
||||
} else {
|
||||
bcx.cond_br(discr.immediate(), lltrue, llfalse);
|
||||
|
|
|
@ -83,7 +83,6 @@ impl<'tcx> Const<'tcx> {
|
|||
let u = v.as_u64(ccx.tcx().sess.target.uint_type);
|
||||
(C_integral(Type::int(ccx), u, false), tcx.types.usize)
|
||||
},
|
||||
Infer(_) | InferSigned(_) => bug!("MIR must not use `{:?}`", ci),
|
||||
};
|
||||
Const { llval: llval, ty: ty }
|
||||
}
|
||||
|
@ -97,14 +96,13 @@ impl<'tcx> Const<'tcx> {
|
|||
let val = match cv {
|
||||
ConstVal::Float(F32(v)) => C_floating_f64(v as f64, llty),
|
||||
ConstVal::Float(F64(v)) => C_floating_f64(v, llty),
|
||||
ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv),
|
||||
ConstVal::Bool(v) => C_bool(ccx, v),
|
||||
ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
|
||||
ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
|
||||
ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
|
||||
ConstVal::Struct(_) | ConstVal::Tuple(_) |
|
||||
ConstVal::Array(..) | ConstVal::Repeat(..) |
|
||||
ConstVal::Function(_) => {
|
||||
ConstVal::Function(..) => {
|
||||
bug!("MIR must not use `{:?}` (which refers to a local ID)", cv)
|
||||
}
|
||||
ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
|
||||
|
@ -249,7 +247,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
args: IndexVec<mir::Local, Const<'tcx>>)
|
||||
-> Result<Const<'tcx>, ConstEvalErr> {
|
||||
-> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
|
||||
let instance = instance.resolve_const(ccx.shared());
|
||||
let mir = ccx.tcx().item_mir(instance.def);
|
||||
MirConstContext::new(ccx, &mir, instance.substs, args).trans()
|
||||
|
@ -263,7 +261,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
value)
|
||||
}
|
||||
|
||||
fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> {
|
||||
fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
|
||||
let tcx = self.ccx.tcx();
|
||||
let mut bb = mir::START_BLOCK;
|
||||
|
||||
|
@ -325,7 +323,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
};
|
||||
|
||||
let err = ConstEvalErr{ span: span, kind: err };
|
||||
report_const_eval_err(tcx, &err, span, "expression").emit();
|
||||
report_const_eval_err(tcx, &err, span, "expression");
|
||||
failure = Err(err);
|
||||
}
|
||||
target
|
||||
|
@ -373,7 +371,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
|
||||
-> Result<ConstLvalue<'tcx>, ConstEvalErr> {
|
||||
-> Result<ConstLvalue<'tcx>, ConstEvalErr<'tcx>> {
|
||||
let tcx = self.ccx.tcx();
|
||||
|
||||
if let mir::Lvalue::Local(index) = *lvalue {
|
||||
|
@ -468,7 +466,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
|
||||
-> Result<Const<'tcx>, ConstEvalErr> {
|
||||
-> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
|
||||
debug!("const_operand({:?} @ {:?})", operand, span);
|
||||
let result = match *operand {
|
||||
mir::Operand::Consume(ref lvalue) => {
|
||||
|
@ -523,7 +521,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
|
||||
fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
|
||||
dest_ty: Ty<'tcx>, span: Span)
|
||||
-> Result<Const<'tcx>, ConstEvalErr> {
|
||||
-> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
|
||||
let tcx = self.ccx.tcx();
|
||||
debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span);
|
||||
let val = match *rvalue {
|
||||
|
@ -961,8 +959,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
|
||||
pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
|
||||
-> Result<ValueRef, ConstEvalErr> {
|
||||
pub fn trans_static_initializer<'a, 'tcx>(
|
||||
ccx: &CrateContext<'a, 'tcx>,
|
||||
def_id: DefId)
|
||||
-> Result<ValueRef, ConstEvalErr<'tcx>>
|
||||
{
|
||||
let instance = Instance::mono(ccx.shared(), def_id);
|
||||
MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)
|
||||
}
|
||||
|
|
|
@ -189,7 +189,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
&item_segment.parameters,
|
||||
None);
|
||||
|
||||
assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
|
||||
assoc_bindings.first().map(|b| self.prohibit_projection(b.span));
|
||||
|
||||
substs
|
||||
}
|
||||
|
@ -446,7 +446,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
trait_def_id,
|
||||
self_ty,
|
||||
trait_segment);
|
||||
assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
|
||||
assoc_bindings.first().map(|b| self.prohibit_projection(b.span));
|
||||
ty::TraitRef::new(trait_def_id, substs)
|
||||
}
|
||||
|
||||
|
@ -844,7 +844,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
|
||||
debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name);
|
||||
|
||||
tcx.prohibit_type_params(slice::ref_slice(item_segment));
|
||||
self.prohibit_type_params(slice::ref_slice(item_segment));
|
||||
|
||||
// Find the type of the associated item, and the trait where the associated
|
||||
// item is declared.
|
||||
|
@ -917,7 +917,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
{
|
||||
let tcx = self.tcx();
|
||||
|
||||
tcx.prohibit_type_params(slice::ref_slice(item_segment));
|
||||
self.prohibit_type_params(slice::ref_slice(item_segment));
|
||||
|
||||
let self_ty = if let Some(ty) = opt_self_ty {
|
||||
ty
|
||||
|
@ -942,6 +942,36 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
self.projected_ty(span, trait_ref, item_segment.name)
|
||||
}
|
||||
|
||||
pub fn prohibit_type_params(&self, segments: &[hir::PathSegment]) {
|
||||
for segment in segments {
|
||||
for typ in segment.parameters.types() {
|
||||
struct_span_err!(self.tcx().sess, typ.span, E0109,
|
||||
"type parameters are not allowed on this type")
|
||||
.span_label(typ.span, &format!("type parameter not allowed"))
|
||||
.emit();
|
||||
break;
|
||||
}
|
||||
for lifetime in segment.parameters.lifetimes() {
|
||||
struct_span_err!(self.tcx().sess, lifetime.span, E0110,
|
||||
"lifetime parameters are not allowed on this type")
|
||||
.span_label(lifetime.span,
|
||||
&format!("lifetime parameter not allowed on this type"))
|
||||
.emit();
|
||||
break;
|
||||
}
|
||||
for binding in segment.parameters.bindings() {
|
||||
self.prohibit_projection(binding.span);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prohibit_projection(&self, span: Span) {
|
||||
let mut err = struct_span_err!(self.tcx().sess, span, E0229,
|
||||
"associated type bindings are not allowed here");
|
||||
err.span_label(span, &format!("associate type not allowed here")).emit();
|
||||
}
|
||||
|
||||
// Check a type Path and convert it to a Ty.
|
||||
pub fn def_to_ty(&self,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
|
@ -957,21 +987,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
match path.def {
|
||||
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => {
|
||||
assert_eq!(opt_self_ty, None);
|
||||
tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
|
||||
self.prohibit_type_params(path.segments.split_last().unwrap().1);
|
||||
self.ast_path_to_ty(span, did, path.segments.last().unwrap())
|
||||
}
|
||||
Def::Variant(did) if permit_variants => {
|
||||
// Convert "variant type" as if it were a real type.
|
||||
// The resulting `Ty` is type of the variant's enum for now.
|
||||
assert_eq!(opt_self_ty, None);
|
||||
tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
|
||||
self.prohibit_type_params(path.segments.split_last().unwrap().1);
|
||||
self.ast_path_to_ty(span,
|
||||
tcx.parent_def_id(did).unwrap(),
|
||||
path.segments.last().unwrap())
|
||||
}
|
||||
Def::TyParam(did) => {
|
||||
assert_eq!(opt_self_ty, None);
|
||||
tcx.prohibit_type_params(&path.segments);
|
||||
self.prohibit_type_params(&path.segments);
|
||||
|
||||
let node_id = tcx.hir.as_local_node_id(did).unwrap();
|
||||
let item_id = tcx.hir.get_parent_node(node_id);
|
||||
|
@ -984,7 +1014,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
// Self in impl (we know the concrete type).
|
||||
|
||||
assert_eq!(opt_self_ty, None);
|
||||
tcx.prohibit_type_params(&path.segments);
|
||||
self.prohibit_type_params(&path.segments);
|
||||
|
||||
let ty = ty::queries::ty::get(tcx, span, def_id);
|
||||
if let Some(free_substs) = self.get_free_substs() {
|
||||
|
@ -996,11 +1026,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
Def::SelfTy(Some(_), None) => {
|
||||
// Self in trait.
|
||||
assert_eq!(opt_self_ty, None);
|
||||
tcx.prohibit_type_params(&path.segments);
|
||||
self.prohibit_type_params(&path.segments);
|
||||
tcx.mk_self_type()
|
||||
}
|
||||
Def::AssociatedTy(def_id) => {
|
||||
tcx.prohibit_type_params(&path.segments[..path.segments.len()-2]);
|
||||
self.prohibit_type_params(&path.segments[..path.segments.len()-2]);
|
||||
let trait_did = tcx.parent_def_id(def_id).unwrap();
|
||||
self.qpath_to_ty(span,
|
||||
opt_self_ty,
|
||||
|
@ -1010,7 +1040,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
Def::PrimTy(prim_ty) => {
|
||||
assert_eq!(opt_self_ty, None);
|
||||
tcx.prim_ty_to_ty(&path.segments, prim_ty)
|
||||
self.prohibit_type_params(&path.segments);
|
||||
match prim_ty {
|
||||
hir::TyBool => tcx.types.bool,
|
||||
hir::TyChar => tcx.types.char,
|
||||
hir::TyInt(it) => tcx.mk_mach_int(it),
|
||||
hir::TyUint(uit) => tcx.mk_mach_uint(uit),
|
||||
hir::TyFloat(ft) => tcx.mk_mach_float(ft),
|
||||
hir::TyStr => tcx.mk_str()
|
||||
}
|
||||
}
|
||||
Def::Err => {
|
||||
self.set_tainted_by_errors();
|
||||
|
|
|
@ -432,10 +432,6 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
|||
|
||||
body_id: ast::NodeId,
|
||||
|
||||
// This flag is set to true if, during the writeback phase, we encounter
|
||||
// a type error in this function.
|
||||
writeback_errors: Cell<bool>,
|
||||
|
||||
// Number of errors that had been reported when we started
|
||||
// checking this function. On exit, if we find that *more* errors
|
||||
// have been reported, we will skip regionck and other work that
|
||||
|
@ -1493,7 +1489,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
FnCtxt {
|
||||
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
|
||||
body_id: body_id,
|
||||
writeback_errors: Cell::new(false),
|
||||
err_count_on_creation: inh.tcx.sess.err_count(),
|
||||
ret_ty: rty,
|
||||
ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal,
|
||||
|
@ -1609,6 +1604,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
|
||||
if ty.references_error() {
|
||||
self.has_errors.set(true);
|
||||
self.set_tainted_by_errors();
|
||||
}
|
||||
|
||||
// FIXME(canndrew): This is_never should probably be an is_uninhabited
|
||||
|
@ -4326,7 +4322,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
// errors if type parameters are provided in an inappropriate place.
|
||||
let poly_segments = type_segment.is_some() as usize +
|
||||
fn_segment.is_some() as usize;
|
||||
self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]);
|
||||
AstConv::prohibit_type_params(self, &segments[..segments.len() - poly_segments]);
|
||||
|
||||
match def {
|
||||
Def::Local(def_id) | Def::Upvar(def_id, ..) => {
|
||||
|
|
|
@ -20,7 +20,6 @@ use rustc::ty::fold::{TypeFolder,TypeFoldable};
|
|||
use rustc::infer::{InferCtxt, FixupError};
|
||||
use rustc::util::nodemap::{DefIdMap, DefIdSet};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::mem;
|
||||
|
||||
use syntax::ast;
|
||||
|
@ -35,8 +34,6 @@ use rustc::hir;
|
|||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body)
|
||||
-> &'gcx ty::TypeckTables<'gcx> {
|
||||
assert_eq!(self.writeback_errors.get(), false);
|
||||
|
||||
let item_id = self.tcx.hir.body_owner(body.id());
|
||||
let item_def_id = self.tcx.hir.local_def_id(item_id);
|
||||
|
||||
|
@ -59,6 +56,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
|
||||
wbcx.tables.used_trait_imports = used_trait_imports;
|
||||
|
||||
wbcx.tables.tainted_by_errors = self.is_tainted_by_errors();
|
||||
|
||||
self.tcx.alloc_tables(wbcx.tables)
|
||||
}
|
||||
}
|
||||
|
@ -195,19 +194,11 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_stmt(&mut self, s: &'gcx hir::Stmt) {
|
||||
if self.fcx.writeback_errors.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.visit_node_id(ResolvingExpr(s.span), s.node.id());
|
||||
intravisit::walk_stmt(self, s);
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, e: &'gcx hir::Expr) {
|
||||
if self.fcx.writeback_errors.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.fix_scalar_builtin_expr(e);
|
||||
|
||||
self.visit_node_id(ResolvingExpr(e.span), e.id);
|
||||
|
@ -227,29 +218,16 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_block(&mut self, b: &'gcx hir::Block) {
|
||||
if self.fcx.writeback_errors.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.visit_node_id(ResolvingExpr(b.span), b.id);
|
||||
intravisit::walk_block(self, b);
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, p: &'gcx hir::Pat) {
|
||||
if self.fcx.writeback_errors.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.visit_node_id(ResolvingPattern(p.span), p.id);
|
||||
|
||||
intravisit::walk_pat(self, p);
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, l: &'gcx hir::Local) {
|
||||
if self.fcx.writeback_errors.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
let var_ty = self.fcx.local_ty(l.span, l.id);
|
||||
let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
|
||||
self.write_ty_to_tables(l.id, var_ty);
|
||||
|
@ -259,10 +237,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
|
|||
|
||||
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
||||
fn visit_upvar_borrow_map(&mut self) {
|
||||
if self.fcx.writeback_errors.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
for (upvar_id, upvar_capture) in self.fcx.tables.borrow().upvar_capture_map.iter() {
|
||||
let new_upvar_capture = match *upvar_capture {
|
||||
ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
|
||||
|
@ -281,10 +255,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_closures(&mut self) {
|
||||
if self.fcx.writeback_errors.get() {
|
||||
return
|
||||
}
|
||||
|
||||
for (&id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() {
|
||||
let closure_ty = self.resolve(closure_ty, ResolvingClosure(id));
|
||||
self.tables.closure_tys.insert(id, closure_ty);
|
||||
|
@ -296,27 +266,15 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_cast_types(&mut self) {
|
||||
if self.fcx.writeback_errors.get() {
|
||||
return
|
||||
}
|
||||
|
||||
self.tables.cast_kinds.extend(
|
||||
self.fcx.tables.borrow().cast_kinds.iter().map(|(&key, &value)| (key, value)));
|
||||
}
|
||||
|
||||
fn visit_lints(&mut self) {
|
||||
if self.fcx.writeback_errors.get() {
|
||||
return
|
||||
}
|
||||
|
||||
self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints);
|
||||
}
|
||||
|
||||
fn visit_anon_types(&mut self) {
|
||||
if self.fcx.writeback_errors.get() {
|
||||
return
|
||||
}
|
||||
|
||||
let gcx = self.tcx().global_tcx();
|
||||
for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
|
||||
let reason = ResolvingAnonTy(node_id);
|
||||
|
@ -542,7 +500,6 @@ impl<'a, 'gcx, 'tcx> ResolveReason {
|
|||
struct Resolver<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
writeback_errors: &'cx Cell<bool>,
|
||||
reason: ResolveReason,
|
||||
}
|
||||
|
||||
|
@ -551,22 +508,19 @@ impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> {
|
|||
reason: ResolveReason)
|
||||
-> Resolver<'cx, 'gcx, 'tcx>
|
||||
{
|
||||
Resolver::from_infcx(fcx, &fcx.writeback_errors, reason)
|
||||
Resolver::from_infcx(fcx, reason)
|
||||
}
|
||||
|
||||
fn from_infcx(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
writeback_errors: &'cx Cell<bool>,
|
||||
reason: ResolveReason)
|
||||
-> Resolver<'cx, 'gcx, 'tcx>
|
||||
{
|
||||
Resolver { infcx: infcx,
|
||||
tcx: infcx.tcx,
|
||||
writeback_errors: writeback_errors,
|
||||
reason: reason }
|
||||
}
|
||||
|
||||
fn report_error(&self, e: FixupError) {
|
||||
self.writeback_errors.set(true);
|
||||
if !self.tcx.sess.has_errors() {
|
||||
match self.reason {
|
||||
ResolvingExpr(span) => {
|
||||
|
|
|
@ -59,7 +59,6 @@ use constrained_type_params as ctp;
|
|||
use middle::lang_items::SizedTraitLangItem;
|
||||
use middle::const_val::ConstVal;
|
||||
use middle::resolve_lifetime as rl;
|
||||
use rustc_const_eval::EvalHint::UncheckedExprHint;
|
||||
use rustc_const_eval::{ConstContext, report_const_eval_err};
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{ToPredicate, ReprOptions};
|
||||
|
@ -75,7 +74,7 @@ use rustc_const_math::ConstInt;
|
|||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use syntax::{abi, ast, attr};
|
||||
use syntax::{abi, ast};
|
||||
use syntax::codemap::Spanned;
|
||||
use syntax::symbol::{Symbol, keywords};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
@ -596,6 +595,17 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
tcx.item_predicates(def_id);
|
||||
}
|
||||
|
||||
fn evaluate_disr_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
body: hir::BodyId)
|
||||
-> Result<ConstVal<'tcx>, ()> {
|
||||
let e = &tcx.hir.body(body).value;
|
||||
ConstContext::new(tcx, body).eval(e).map_err(|err| {
|
||||
// enum variant evaluation happens before the global constant check
|
||||
// so we need to report the real error
|
||||
report_const_eval_err(tcx, &err, e.span, "enum discriminant");
|
||||
})
|
||||
}
|
||||
|
||||
fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
variants: &[hir::Variant]) {
|
||||
|
@ -610,7 +620,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
prev_discr = Some(if let Some(e) = variant.node.disr_expr {
|
||||
let expr_did = tcx.hir.local_def_id(e.node_id);
|
||||
let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || {
|
||||
evaluate_disr_expr(tcx, repr_type, e).map(ConstVal::Integral)
|
||||
evaluate_disr_expr(tcx, e)
|
||||
});
|
||||
|
||||
match result {
|
||||
|
@ -738,60 +748,6 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
tcx.alloc_adt_def(def_id, kind, variants, repr)
|
||||
}
|
||||
|
||||
fn evaluate_disr_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
repr_ty: attr::IntType,
|
||||
body: hir::BodyId)
|
||||
-> Result<ConstInt, ()> {
|
||||
let e = &tcx.hir.body(body).value;
|
||||
debug!("disr expr, checking {}", tcx.hir.node_to_pretty_string(e.id));
|
||||
|
||||
let ty_hint = repr_ty.to_ty(tcx);
|
||||
let print_err = |cv: ConstVal| {
|
||||
struct_span_err!(tcx.sess, e.span, E0079, "mismatched types")
|
||||
.note_expected_found(&"type", &ty_hint, &format!("{}", cv.description()))
|
||||
.span_label(e.span, &format!("expected '{}' type", ty_hint))
|
||||
.emit();
|
||||
};
|
||||
|
||||
let hint = UncheckedExprHint(ty_hint);
|
||||
match ConstContext::new(tcx, body).eval(e, hint) {
|
||||
Ok(ConstVal::Integral(i)) => {
|
||||
// FIXME: eval should return an error if the hint does not match the type of the body.
|
||||
// i.e. eventually the match below would not exist.
|
||||
match (repr_ty, i) {
|
||||
(attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) |
|
||||
(attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) |
|
||||
(attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) |
|
||||
(attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) |
|
||||
(attr::SignedInt(ast::IntTy::I128), ConstInt::I128(_)) |
|
||||
(attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) |
|
||||
(attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) |
|
||||
(attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) |
|
||||
(attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) |
|
||||
(attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) |
|
||||
(attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) |
|
||||
(attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => Ok(i),
|
||||
(_, i) => {
|
||||
print_err(ConstVal::Integral(i));
|
||||
Err(())
|
||||
},
|
||||
}
|
||||
},
|
||||
Ok(cv) => {
|
||||
print_err(cv);
|
||||
Err(())
|
||||
},
|
||||
// enum variant evaluation happens before the global constant check
|
||||
// so we need to report the real error
|
||||
Err(err) => {
|
||||
let mut diag = report_const_eval_err(
|
||||
tcx, &err, e.span, "enum discriminant");
|
||||
diag.emit();
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures that the super-predicates of the trait with def-id
|
||||
/// trait_def_id are converted and stored. This also ensures that
|
||||
/// the transitive super-predicates are converted;
|
||||
|
|
|
@ -1039,45 +1039,6 @@ struct Good(u32, u32, u32);
|
|||
```
|
||||
"##,
|
||||
|
||||
E0079: r##"
|
||||
Enum variants which contain no data can be given a custom integer
|
||||
representation. This error indicates that the value provided is not an integer
|
||||
literal and is therefore invalid.
|
||||
|
||||
For example, in the following code:
|
||||
|
||||
```compile_fail,E0079
|
||||
enum Foo {
|
||||
Q = "32",
|
||||
}
|
||||
```
|
||||
|
||||
We try to set the representation to a string.
|
||||
|
||||
There's no general fix for this; if you can work with an integer then just set
|
||||
it to one:
|
||||
|
||||
```
|
||||
enum Foo {
|
||||
Q = 32,
|
||||
}
|
||||
```
|
||||
|
||||
However if you actually wanted a mapping between variants and non-integer
|
||||
objects, it may be preferable to use a method with a match instead:
|
||||
|
||||
```
|
||||
enum Foo { Q }
|
||||
impl Foo {
|
||||
fn get_str(&self) -> &'static str {
|
||||
match *self {
|
||||
Foo::Q => "32",
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
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,
|
||||
|
@ -1427,6 +1388,44 @@ struct Baz<'a> {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0109: r##"
|
||||
You tried to give a type parameter to a type which doesn't need it. Erroneous
|
||||
code example:
|
||||
|
||||
```compile_fail,E0109
|
||||
type X = u32<i32>; // error: type parameters are not allowed on this type
|
||||
```
|
||||
|
||||
Please check that you used the correct type and recheck its definition. Perhaps
|
||||
it doesn't need the type parameter.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
type X = u32; // this compiles
|
||||
```
|
||||
|
||||
Note that type parameters for enum-variant constructors go after the variant,
|
||||
not after the enum (Option::None::<u32>, not Option::<u32>::None).
|
||||
"##,
|
||||
|
||||
E0110: r##"
|
||||
You tried to give a lifetime parameter to a type which doesn't need it.
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0110
|
||||
type X = u32<'static>; // error: lifetime parameters are not allowed on
|
||||
// this type
|
||||
```
|
||||
|
||||
Please check that the correct type was used and recheck its definition; perhaps
|
||||
it doesn't need the lifetime parameter. Example:
|
||||
|
||||
```
|
||||
type X = u32; // ok!
|
||||
```
|
||||
"##,
|
||||
|
||||
E0116: r##"
|
||||
You can only define an inherent implementation for a type in the same crate
|
||||
where the type was defined. For example, an `impl` block as below is not allowed
|
||||
|
@ -2649,6 +2648,41 @@ fn main() {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0229: r##"
|
||||
An associated type binding was done outside of the type parameter declaration
|
||||
and `where` clause. Erroneous code example:
|
||||
|
||||
```compile_fail,E0229
|
||||
pub trait Foo {
|
||||
type A;
|
||||
fn boo(&self) -> <Self as Foo>::A;
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl Foo for isize {
|
||||
type A = usize;
|
||||
fn boo(&self) -> usize { 42 }
|
||||
}
|
||||
|
||||
fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
|
||||
// error: associated type bindings are not allowed here
|
||||
```
|
||||
|
||||
To solve this error, please move the type bindings in the type parameter
|
||||
declaration:
|
||||
|
||||
```ignore
|
||||
fn baz<I: Foo<A=Bar>>(x: &<I as Foo>::A) {} // ok!
|
||||
```
|
||||
|
||||
Or in the `where` clause:
|
||||
|
||||
```ignore
|
||||
fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0230: r##"
|
||||
The trait has more type parameters specified than appear in its definition.
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
// 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.
|
||||
|
||||
const A: [u32; "hello"] = [];
|
||||
//~^ ERROR expected `usize` for array length, found string literal [E0306]
|
||||
//~| NOTE expected `usize`
|
||||
|
||||
const B: [u32; true] = [];
|
||||
//~^ ERROR expected `usize` for array length, found boolean [E0306]
|
||||
//~| NOTE expected `usize`
|
||||
|
||||
const C: [u32; 0.0] = [];
|
||||
//~^ ERROR expected `usize` for array length, found float [E0306]
|
||||
//~| NOTE expected `usize`
|
||||
|
||||
fn main() {
|
||||
}
|
|
@ -14,7 +14,8 @@ trait Foo {
|
|||
const ID: usize;
|
||||
}
|
||||
|
||||
const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0080
|
||||
const X: [i32; <i32 as Foo>::ID] = [0, 1, 2];
|
||||
//~^ ERROR the trait bound `i32: Foo` is not satisfied
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, X);
|
||||
|
|
|
@ -27,8 +27,6 @@ impl Foo for Def {
|
|||
pub fn test<A: Foo, B: Foo>() {
|
||||
let _array = [4; <A as Foo>::Y];
|
||||
//~^ ERROR cannot use an outer type parameter in this context [E0402]
|
||||
//~| ERROR constant evaluation error [E0080]
|
||||
//~| non-constant path in constant
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -27,8 +27,6 @@ impl Foo for Def {
|
|||
pub fn test<A: Foo, B: Foo>() {
|
||||
let _array: [u32; <A as Foo>::Y];
|
||||
//~^ ERROR cannot use an outer type parameter in this context [E0402]
|
||||
//~| ERROR constant evaluation error [E0080]
|
||||
//~| non-constant path in constant
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
#![feature(const_indexing)]
|
||||
|
||||
const FOO: [u32; 3] = [1, 2, 3];
|
||||
const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval
|
||||
const FOO: [usize; 3] = [1, 2, 3];
|
||||
const BAR: usize = FOO[5]; // no error, because the error below occurs before regular const eval
|
||||
|
||||
const BLUB: [u32; FOO[4]] = [5, 6];
|
||||
//~^ ERROR constant evaluation error [E0080]
|
||||
|
|
|
@ -20,8 +20,9 @@ use std::{u8, u16, u32, u64, usize};
|
|||
|
||||
const A_I8_T
|
||||
: [u32; (i8::MAX as i8 + 1u8) as usize]
|
||||
//~^ ERROR constant evaluation error [E0080]
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected i8, found u8
|
||||
//~| ERROR the trait bound `i8: std::ops::Add<u8>` is not satisfied
|
||||
= [0; (i8::MAX as usize) + 1];
|
||||
|
||||
|
||||
|
@ -32,8 +33,7 @@ const A_CHAR_USIZE
|
|||
|
||||
const A_BAD_CHAR_USIZE
|
||||
: [u32; 5i8 as char as usize]
|
||||
//~^ ERROR constant evaluation error
|
||||
//~| only `u8` can be cast as `char`, not `i8`
|
||||
//~^ ERROR only `u8` can be cast as `char`, not `i8`
|
||||
= [0; 5];
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -14,12 +14,13 @@
|
|||
struct S(i32);
|
||||
|
||||
const CONSTANT: S = S(0);
|
||||
//~^ ERROR E0080
|
||||
//~| unimplemented constant expression: tuple struct constructors
|
||||
|
||||
enum E {
|
||||
V = CONSTANT,
|
||||
//~^ NOTE: for enum discriminant here
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected isize, found struct `S`
|
||||
//~| NOTE expected type `isize`
|
||||
//~| found type `S`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -8,52 +8,71 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
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 X: usize = 42 && 39;
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected bool, found integral variable
|
||||
//~| ERROR mismatched types
|
||||
//~| expected bool, found integral variable
|
||||
//~| ERROR mismatched types
|
||||
//~| expected usize, found bool
|
||||
const ARR: [i32; X] = [99; 34];
|
||||
|
||||
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 X1: usize = 42 || 39;
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected bool, found integral variable
|
||||
//~| ERROR mismatched types
|
||||
//~| expected bool, found integral variable
|
||||
//~| ERROR mismatched types
|
||||
//~| expected usize, found bool
|
||||
const ARR1: [i32; X1] = [99; 47];
|
||||
|
||||
const X2: usize = -42 || -39; //~ ERROR E0080
|
||||
//~| unary negation of unsigned integer
|
||||
const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
|
||||
const X2: usize = -42 || -39;
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected bool, found integral variable
|
||||
//~| ERROR mismatched types
|
||||
//~| expected bool, found integral variable
|
||||
//~| ERROR mismatched types
|
||||
//~| expected usize, found bool
|
||||
const ARR2: [i32; X2] = [99; 18446744073709551607];
|
||||
|
||||
const X3: usize = -42 && -39; //~ ERROR E0080
|
||||
//~| unary negation of unsigned integer
|
||||
const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
|
||||
const X3: usize = -42 && -39;
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected bool, found integral variable
|
||||
//~| ERROR mismatched types
|
||||
//~| expected bool, found integral variable
|
||||
//~| ERROR mismatched types
|
||||
//~| expected usize, found bool
|
||||
const ARR3: [i32; X3] = [99; 6];
|
||||
|
||||
const Y: usize = 42.0 == 42.0;
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected usize, found bool
|
||||
const ARRR: [i32; Y] = [99; 1];
|
||||
//~^ ERROR: expected `usize` for array length, found boolean [E0306]
|
||||
//~| NOTE expected `usize`
|
||||
|
||||
const Y1: usize = 42.0 >= 42.0;
|
||||
const ARRR1: [i32; Y] = [99; 1];
|
||||
//~^ ERROR: expected `usize` for array length, found boolean [E0306]
|
||||
//~| NOTE expected `usize`
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected usize, found bool
|
||||
const ARRR1: [i32; Y1] = [99; 1];
|
||||
|
||||
const Y2: usize = 42.0 <= 42.0;
|
||||
const ARRR2: [i32; Y] = [99; 1];
|
||||
//~^ ERROR: expected `usize` for array length, found boolean [E0306]
|
||||
//~| NOTE expected `usize`
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected usize, found bool
|
||||
const ARRR2: [i32; Y2] = [99; 1];
|
||||
|
||||
const Y3: usize = 42.0 > 42.0;
|
||||
const ARRR3: [i32; Y] = [99; 0];
|
||||
//~^ ERROR: expected `usize` for array length, found boolean [E0306]
|
||||
//~| NOTE expected `usize`
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected usize, found bool
|
||||
const ARRR3: [i32; Y3] = [99; 0];
|
||||
|
||||
const Y4: usize = 42.0 < 42.0;
|
||||
const ARRR4: [i32; Y] = [99; 0];
|
||||
//~^ ERROR: expected `usize` for array length, found boolean [E0306]
|
||||
//~| NOTE expected `usize`
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected usize, found bool
|
||||
const ARRR4: [i32; Y4] = [99; 0];
|
||||
|
||||
const Y5: usize = 42.0 != 42.0;
|
||||
const ARRR5: [i32; Y] = [99; 0];
|
||||
//~^ ERROR: expected `usize` for array length, found boolean [E0306]
|
||||
//~| NOTE expected `usize`
|
||||
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected usize, found bool
|
||||
const ARRR5: [i32; Y5] = [99; 0];
|
||||
|
||||
fn main() {
|
||||
let _ = ARR;
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
// Test spans of errors
|
||||
|
||||
const TUP: (usize,) = 5usize << 64;
|
||||
//~^ ERROR E0080
|
||||
//~| attempt to shift left with overflow
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected tuple, found usize
|
||||
const ARR: [i32; TUP.0] = [];
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -25,7 +25,7 @@ fn f_i8() {
|
|||
Ok = i8::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_u8,
|
||||
//~^ ERROR E0080
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected i8, found u8
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ fn f_u8() {
|
|||
Ok = u8::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_i8,
|
||||
//~^ ERROR E0080
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected u8, found i8
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ fn f_i16() {
|
|||
Ok = i16::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_u16,
|
||||
//~^ ERROR E0080
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected i16, found u16
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ fn f_u16() {
|
|||
Ok = u16::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_i16,
|
||||
//~^ ERROR E0080
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected u16, found i16
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ fn f_i32() {
|
|||
Ok = i32::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_u32,
|
||||
//~^ ERROR E0080
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected i32, found u32
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ fn f_u32() {
|
|||
Ok = u32::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_i32,
|
||||
//~^ ERROR E0080
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected u32, found i32
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ fn f_i64() {
|
|||
Ok = i64::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_u64,
|
||||
//~^ ERROR E0080
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected i64, found u64
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ fn f_u64() {
|
|||
Ok = u64::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_i64,
|
||||
//~^ ERROR E0080
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected u64, found i64
|
||||
}
|
||||
|
||||
|
|
|
@ -13,32 +13,32 @@
|
|||
enum Eu8 {
|
||||
Au8 = 23,
|
||||
Bu8 = 223,
|
||||
Cu8 = -23, //~ ERROR E0080
|
||||
//~| unary negation of unsigned integer
|
||||
Cu8 = -23,
|
||||
//~^ ERROR cannot apply unary operator `-` to type `u8`
|
||||
}
|
||||
|
||||
#[repr(u16)]
|
||||
enum Eu16 {
|
||||
Au16 = 23,
|
||||
Bu16 = 55555,
|
||||
Cu16 = -22333, //~ ERROR E0080
|
||||
//~| unary negation of unsigned integer
|
||||
Cu16 = -22333,
|
||||
//~^ ERROR cannot apply unary operator `-` to type `u16`
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
enum Eu32 {
|
||||
Au32 = 23,
|
||||
Bu32 = 3_000_000_000,
|
||||
Cu32 = -2_000_000_000, //~ ERROR E0080
|
||||
//~| unary negation of unsigned integer
|
||||
Cu32 = -2_000_000_000,
|
||||
//~^ ERROR cannot apply unary operator `-` to type `u32`
|
||||
}
|
||||
|
||||
#[repr(u64)]
|
||||
enum Eu64 {
|
||||
Au32 = 23,
|
||||
Bu32 = 3_000_000_000,
|
||||
Cu32 = -2_000_000_000, //~ ERROR E0080
|
||||
//~| unary negation of unsigned integer
|
||||
Cu32 = -2_000_000_000,
|
||||
//~^ ERROR cannot apply unary operator `-` to type `u64`
|
||||
}
|
||||
|
||||
// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a
|
||||
|
|
|
@ -10,6 +10,5 @@
|
|||
|
||||
fn main() {
|
||||
fn f(a: [u8; u32::DOESNOTEXIST]) {}
|
||||
//~^ ERROR constant evaluation error
|
||||
//~| unresolved path in constant expression
|
||||
//~^ ERROR no associated item named `DOESNOTEXIST` found for type `u32`
|
||||
}
|
||||
|
|
|
@ -12,12 +12,10 @@ 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 no associated item named `PIE` found for type `Delicious`
|
||||
}
|
||||
|
||||
const FOO: [u32; u8::MIN as usize] = [];
|
||||
//~^ ERROR constant evaluation error
|
||||
//~| unresolved path in constant expression
|
||||
//~^ ERROR no associated item named `MIN` found for type `u8`
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
|
||||
pub enum SomeEnum {
|
||||
B = SomeEnum::A,
|
||||
//~^ ERROR constant evaluation error
|
||||
//~| unresolved path in constant expression
|
||||
//~^ ERROR no associated item named `A` found for type `SomeEnum`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
// Regression test for issue #28586
|
||||
|
||||
pub trait Foo {}
|
||||
impl Foo for [u8; usize::BYTES] {} //~ ERROR E0080
|
||||
impl Foo for [u8; usize::BYTES] {}
|
||||
//~^ ERROR no associated item named `BYTES` found for type `usize`
|
||||
|
||||
fn main() { }
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#![feature(associated_consts)]
|
||||
|
||||
enum Enum<T: Trait> {
|
||||
X = Trait::Number, //~ ERROR constant evaluation error
|
||||
X = Trait::Number,
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected isize, found i32
|
||||
}
|
||||
|
||||
trait Trait {
|
||||
|
|
|
@ -15,9 +15,7 @@ fn main() {
|
|||
enum Stuff {
|
||||
Bar = foo
|
||||
//~^ ERROR attempt to use a non-constant value in a constant
|
||||
//~^^ ERROR constant evaluation error
|
||||
//~| unresolved path in constant expression
|
||||
}
|
||||
|
||||
println!("{}", Stuff::Bar);
|
||||
println!("{:?}", Stuff::Bar);
|
||||
}
|
||||
|
|
|
@ -23,9 +23,13 @@ impl Dim for Dim3 {
|
|||
pub struct Vector<T, D: Dim> {
|
||||
entries: [T; D::dim()]
|
||||
//~^ ERROR cannot use an outer type parameter in this context
|
||||
//~| ERROR constant evaluation error
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let array: [usize; Dim3::dim()] = [0; Dim3::dim()];
|
||||
let array: [usize; Dim3::dim()]
|
||||
//~^ ERROR constant evaluation error
|
||||
//~| non-constant path in constant expression
|
||||
= [0; Dim3::dim()];
|
||||
//~^ ERROR constant evaluation error
|
||||
//~| non-constant path in constant expression
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
|
||||
enum Foo {
|
||||
A = 1i64,
|
||||
//~^ ERROR constant evaluation error
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected isize, found i64
|
||||
B = 2u8
|
||||
//~^ ERROR constant evaluation error
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected isize, found u8
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,5 @@ fn main() {
|
|||
fn bar(n: isize) {
|
||||
let _x: [isize; n];
|
||||
//~^ ERROR attempt to use a non-constant value in a constant [E0435]
|
||||
//~| ERROR constant evaluation error [E0080]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,5 @@ fn main() {
|
|||
let _x = [0; n];
|
||||
//~^ ERROR attempt to use a non-constant value in a constant [E0435]
|
||||
//~| NOTE non-constant used with constant
|
||||
//~| NOTE unresolved path in constant expression
|
||||
//~| ERROR constant evaluation error [E0080]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ fn main() {
|
|||
// END RUST SOURCE
|
||||
// START rustc.node4.SimplifyBranches.initial-before.mir
|
||||
// bb0: {
|
||||
// switchInt(const false) -> [0: bb2, otherwise: bb1];
|
||||
// switchInt(const false) -> [0u8: bb2, otherwise: bb1];
|
||||
// }
|
||||
// END rustc.node4.SimplifyBranches.initial-before.mir
|
||||
// START rustc.node4.SimplifyBranches.initial-after.mir
|
||||
|
|
|
@ -17,7 +17,7 @@ impl S {
|
|||
}
|
||||
|
||||
static STUFF: [u8; S::N] = [0; S::N];
|
||||
//~^ ERROR constant evaluation error
|
||||
//~| unresolved path in constant expression
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
assert_eq!(STUFF, [0; 3]);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
|
@ -8,10 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
enum Foo {
|
||||
Q = "32" //~ ERROR E0079
|
||||
//~^ expected 'isize' type
|
||||
}
|
||||
type Array = [(); ((1 < 2) == false) as usize];
|
||||
|
||||
fn main() {
|
||||
let _: Array = [];
|
||||
}
|
|
@ -46,11 +46,5 @@ error[E0425]: cannot find value `second` in module `m`
|
|||
32 | let b: m::first = m::second; // Misspelled item in module.
|
||||
| ^^^^^^^^^ did you mean `m::Second`?
|
||||
|
||||
error[E0080]: constant evaluation error
|
||||
--> $DIR/levenshtein.rs:30:20
|
||||
|
|
||||
30 | let v = [0u32; MAXITEM]; // Misspelled constant name.
|
||||
| ^^^^^^^ unresolved path in constant expression
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue