Auto merge of #32628 - Manishearth:rollup, r=Manishearth

Rollup of 4 pull requests

- Successful merges: #32259, #32494, #32612, #32618
- Failed merges: #32562
This commit is contained in:
bors 2016-03-30 16:41:08 -07:00
commit 30a3849f22
84 changed files with 973 additions and 810 deletions

View File

@ -58,7 +58,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
rustc_data_structures rustc_front rustc_platform_intrinsics \
rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \
rustc_const_eval
rustc_const_eval rustc_const_math
HOST_CRATES := syntax syntax_ext $(RUSTC_CRATES) rustdoc fmt_macros \
flate arena graphviz rbml log serialize
TOOLS := compiletest rustdoc rustc rustbook error_index_generator
@ -92,36 +92,39 @@ DEPS_test := std getopts term native:rust_test_helpers
DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode
DEPS_syntax_ext := syntax fmt_macros
DEPS_rustc_const_eval := std syntax
DEPS_rustc_const_math := std syntax log serialize
DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize rustc_front \
rustc_back graphviz
DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml rustc_front\
log graphviz rustc_back rustc_data_structures\
rustc_const_eval
rustc_const_math
DEPS_rustc_back := std syntax rustc_front flate log libc
DEPS_rustc_borrowck := rustc rustc_front rustc_mir log graphviz syntax
DEPS_rustc_data_structures := std log serialize
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
rustc_trans rustc_privacy rustc_lint rustc_front rustc_plugin \
rustc_metadata syntax_ext rustc_passes rustc_save_analysis
rustc_metadata syntax_ext rustc_passes rustc_save_analysis rustc_const_eval
DEPS_rustc_front := std syntax log serialize
DEPS_rustc_lint := rustc log syntax
DEPS_rustc_lint := rustc log syntax rustc_const_eval
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
DEPS_rustc_metadata := rustc rustc_front syntax rbml rustc_const_eval
DEPS_rustc_passes := syntax rustc core rustc_front
DEPS_rustc_mir := rustc rustc_front syntax rustc_const_eval
DEPS_rustc_metadata := rustc rustc_front syntax rbml rustc_const_math
DEPS_rustc_passes := syntax rustc core rustc_front rustc_const_eval
DEPS_rustc_mir := rustc rustc_front syntax rustc_const_math rustc_const_eval
DEPS_rustc_resolve := arena rustc rustc_front log syntax
DEPS_rustc_platform_intrinsics := std
DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
DEPS_rustc_privacy := rustc rustc_front log syntax
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics \
rustc_const_eval
rustc_const_math rustc_const_eval
DEPS_rustc_save_analysis := rustc log syntax rustc_front
DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics rustc_const_eval
DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics rustc_const_math \
rustc_const_eval
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
test rustc_lint rustc_front
test rustc_lint rustc_front rustc_const_eval
TOOL_DEPS_compiletest := test getopts log

View File

@ -131,7 +131,7 @@ declarations.
## Trait objects with associated types
Theres one more bit of syntax we should talk about: trait objects. If you
try to create a trait object from an associated type, like this:
try to create a trait object from a trait with an associated type, like this:
```rust,ignore
# trait Graph {

View File

@ -18,7 +18,7 @@ log = { path = "../liblog" }
rbml = { path = "../librbml" }
rustc_back = { path = "../librustc_back" }
rustc_bitflags = { path = "../librustc_bitflags" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_front = { path = "../librustc_front" }
serialize = { path = "../libserialize" }

View File

@ -14,273 +14,6 @@
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {
E0001: r##"
This error suggests that the expression arm corresponding to the noted pattern
will never be reached as for all possible values of the expression being
matched, one of the preceding patterns will match.
This means that perhaps some of the preceding patterns are too general, this
one is too specific or the ordering is incorrect.
For example, the following `match` block has too many arms:
```compile_fail
match foo {
Some(bar) => {/* ... */}
None => {/* ... */}
_ => {/* ... */} // All possible cases have already been handled
}
```
`match` blocks have their patterns matched in order, so, for example, putting
a wildcard arm above a more specific arm will make the latter arm irrelevant.
Ensure the ordering of the match arm is correct and remove any superfluous
arms.
"##,
E0002: r##"
This error indicates that an empty match expression is invalid because the type
it is matching on is non-empty (there exist values of this type). In safe code
it is impossible to create an instance of an empty type, so empty match
expressions are almost never desired. This error is typically fixed by adding
one or more cases to the match expression.
An example of an empty type is `enum Empty { }`. So, the following will work:
```
enum Empty {}
fn foo(x: Empty) {
match x {
// empty
}
}
```
However, this won't:
```compile_fail
enum Empty {}
fn foo(x: Option<String>) {
match x {
// empty
}
}
```
"##,
E0003: r##"
Not-a-Number (NaN) values cannot be compared for equality and hence can never
match the input to a match expression. So, the following will not compile:
```compile_fail
const NAN: f32 = 0.0 / 0.0;
let number = 0.1f32;
match number {
NAN => { /* ... */ },
_ => {}
}
```
To match against NaN values, you should instead use the `is_nan()` method in a
guard, like so:
```
let number = 0.1f32;
match number {
x if x.is_nan() => { /* ... */ }
_ => {}
}
```
"##,
E0004: r##"
This error indicates that the compiler cannot guarantee a matching pattern for
one or more possible inputs to a match expression. Guaranteed matches are
required in order to assign values to match expressions, or alternatively,
determine the flow of execution. Erroneous code example:
```compile_fail
enum Terminator {
HastaLaVistaBaby,
TalkToMyHand,
}
let x = Terminator::HastaLaVistaBaby;
match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered
Terminator::TalkToMyHand => {}
}
```
If you encounter this error you must alter your patterns so that every possible
value of the input type is matched. For types with a small number of variants
(like enums) you should probably cover all cases explicitly. Alternatively, the
underscore `_` wildcard pattern can be added after all other patterns to match
"anything else". Example:
```
enum Terminator {
HastaLaVistaBaby,
TalkToMyHand,
}
let x = Terminator::HastaLaVistaBaby;
match x {
Terminator::TalkToMyHand => {}
Terminator::HastaLaVistaBaby => {}
}
// or:
match x {
Terminator::TalkToMyHand => {}
_ => {}
}
```
"##,
E0005: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee
that a name will be extracted in all cases. Erroneous code example:
```compile_fail
let x = Some(1);
let Some(y) = x;
// error: refutable pattern in local binding: `None` not covered
```
If you encounter this error you probably need to use a `match` or `if let` to
deal with the possibility of failure. Example:
```compile_fail
let x = Some(1);
match x {
Some(y) => {
// do something
},
None => {}
}
// or:
if let Some(y) = x {
// do something
}
```
"##,
E0007: r##"
This error indicates that the bindings in a match arm would require a value to
be moved into more than one location, thus violating unique ownership. Code
like the following is invalid as it requires the entire `Option<String>` to be
moved into a variable called `op_string` while simultaneously requiring the
inner `String` to be moved into a variable called `s`.
```compile_fail
let x = Some("s".to_string());
match x {
op_string @ Some(s) => {},
None => {},
}
```
See also the error E0303.
"##,
E0008: r##"
Names bound in match arms retain their type in pattern guards. As such, if a
name is bound by move in a pattern, it should also be moved to wherever it is
referenced in the pattern guard code. Doing so however would prevent the name
from being available in the body of the match arm. Consider the following:
```compile_fail
match Some("hi".to_string()) {
Some(s) if s.len() == 0 => {}, // use s.
_ => {},
}
```
The variable `s` has type `String`, and its use in the guard is as a variable of
type `String`. The guard code effectively executes in a separate scope to the
body of the arm, so the value would be moved into this anonymous scope and
therefore become unavailable in the body of the arm. Although this example seems
innocuous, the problem is most clear when considering functions that take their
argument by value.
```compile_fail
match Some("hi".to_string()) {
Some(s) if { drop(s); false } => (),
Some(s) => {}, // use s.
_ => {},
}
```
The value would be dropped in the guard then become unavailable not only in the
body of that arm but also in all subsequent arms! The solution is to bind by
reference when using guards or refactor the entire expression, perhaps by
putting the condition inside the body of the arm.
"##,
E0009: r##"
In a pattern, all values that don't implement the `Copy` trait have to be bound
the same way. The goal here is to avoid binding simultaneously by-move and
by-ref.
This limitation may be removed in a future version of Rust.
Erroneous code example:
```compile_fail
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((y, ref z)) => {},
None => panic!()
}
```
You have two solutions:
Solution #1: Bind the pattern's values the same way.
```
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((ref y, ref z)) => {},
// or Some((y, z)) => {}
None => panic!()
}
```
Solution #2: Implement the `Copy` trait for the `X` structure.
However, please keep in mind that the first solution should be preferred.
```
#[derive(Clone, Copy)]
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((y, ref z)) => {},
None => panic!()
}
```
"##,
E0020: r##"
This error indicates that an attempt was made to divide by zero (or take the
remainder of a zero divisor) in a static or constant expression. Erroneous
@ -762,128 +495,6 @@ attributes:
See also https://doc.rust-lang.org/book/no-stdlib.html
"##,
E0158: r##"
`const` and `static` mean different things. A `const` is a compile-time
constant, an alias for a literal value. This property means you can match it
directly within a pattern.
The `static` keyword, on the other hand, guarantees a fixed location in memory.
This does not always mean that the value is constant. For example, a global
mutex can be declared `static` as well.
If you want to match against a `static`, consider using a guard instead:
```
static FORTY_TWO: i32 = 42;
match Some(42) {
Some(x) if x == FORTY_TWO => {}
_ => {}
}
```
"##,
E0162: r##"
An if-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding instead. For instance:
```compile_fail
struct Irrefutable(i32);
let irr = Irrefutable(0);
// This fails to compile because the match is irrefutable.
if let Irrefutable(x) = irr {
// This body will always be executed.
foo(x);
}
```
Try this instead:
```ignore
struct Irrefutable(i32);
let irr = Irrefutable(0);
let Irrefutable(x) = irr;
foo(x);
```
"##,
E0165: r##"
A while-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding inside a `loop` instead. For instance:
```compile_fail
struct Irrefutable(i32);
let irr = Irrefutable(0);
// This fails to compile because the match is irrefutable.
while let Irrefutable(x) = irr {
...
}
Try this instead:
```
struct Irrefutable(i32);
let irr = Irrefutable(0);
loop {
let Irrefutable(x) = irr;
...
}
```
"##,
E0170: r##"
Enum variants are qualified by default. For example, given this type:
```
enum Method {
GET,
POST,
}
```
You would match it using:
```
enum Method {
GET,
POST,
}
let m = Method::GET;
match m {
Method::GET => {},
Method::POST => {},
}
```
If you don't qualify the names, the code will bind new variables named "GET" and
"POST" instead. This behavior is likely not what you want, so `rustc` warns when
that happens.
Qualified names are good practice, and most code works well with them. But if
you prefer them unqualified, you can import the variants into scope:
```ignore
use Method::*;
enum Method { GET, POST }
```
If you want others to be able to import variants from your module directly, use
`pub use`:
```ignore
pub use Method::*;
enum Method { GET, POST }
```
"##,
E0229: r##"
An associated type binding was done outside of the type parameter declaration
and `where` clause. Erroneous code example:
@ -1573,135 +1184,6 @@ that the value provided is a positive integer between quotes, like so:
```
"##,
E0297: r##"
Patterns used to bind names must be irrefutable. That is, they must guarantee
that a name will be extracted in all cases. Instead of pattern matching the
loop variable, consider using a `match` or `if let` inside the loop body. For
instance:
```compile_fail
let xs : Vec<Option<i32>> = vec!(Some(1), None);
// This fails because `None` is not covered.
for Some(x) in xs {
// ...
}
```
Match inside the loop instead:
```
let xs : Vec<Option<i32>> = vec!(Some(1), None);
for item in xs {
match item {
Some(x) => {},
None => {},
}
}
```
Or use `if let`:
```
let xs : Vec<Option<i32>> = vec!(Some(1), None);
for item in xs {
if let Some(x) = item {
// ...
}
}
```
"##,
E0301: r##"
Mutable borrows are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if mutable
borrows were allowed:
```compile_fail
match Some(()) {
None => { },
option if option.take().is_none() => {
/* impossible, option is `Some` */
},
Some(_) => { } // When the previous match failed, the option became `None`.
}
```
"##,
E0302: r##"
Assignments are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if assignments
were allowed:
```compile_fail
match Some(()) {
None => { },
option if { option = None; false } { },
Some(_) => { } // When the previous match failed, the option became `None`.
}
```
"##,
E0303: r##"
In certain cases it is possible for sub-bindings to violate memory safety.
Updates to the borrow checker in a future version of Rust may remove this
restriction, but for now patterns must be rewritten without sub-bindings.
```ignore
// Before.
match Some("hi".to_string()) {
ref op_string_ref @ Some(s) => {},
None => {},
}
// After.
match Some("hi".to_string()) {
Some(ref s) => {
let op_string_ref = &Some(s);
// ...
},
None => {},
}
```
The `op_string_ref` binding has type `&Option<&String>` in both cases.
See also https://github.com/rust-lang/rust/issues/14587
"##,
E0306: r##"
In an array literal `[x; N]`, `N` is the number of elements in the array. This
must be an unsigned integer. Erroneous code example:
```compile_fail
let x = [0i32; true]; // error: expected positive integer for repeat count,
// found boolean
```
Working example:
```
let x = [0i32; 2];
```
"##,
E0307: r##"
The length of an array is part of its type. For this reason, this length must
be a compile-time constant. Erroneous code example:
```compile_fail
let len = 10;
let x = [0i32; len]; // error: expected constant integer for repeat count,
// found variable
```
"##,
E0308: r##"
This error occurs when the compiler was unable to infer the concrete type of a
variable. It can occur for several cases, the most common of which is a
@ -1991,8 +1473,6 @@ register_diagnostics! {
E0280, // requirement is not satisfied
E0284, // cannot resolve type
// E0285, // overflow evaluation builtin bounds
E0298, // mismatched types between arms
E0299, // mismatched types between arms
// E0300, // unexpanded macro
// E0304, // expected signed integer constant
// E0305, // expected constant
@ -2003,7 +1483,6 @@ register_diagnostics! {
E0315, // cannot invoke closure outside of its lifetime
E0316, // nested quantification of lifetimes
E0453, // overruled by outer forbid
E0471, // constant evaluation error: ..
E0473, // dereference of reference outside its lifetime
E0474, // captured variable `..` does not outlive the enclosing closure
E0475, // index of slice outside its lifetime

View File

@ -55,7 +55,7 @@ extern crate rustc_front;
extern crate rustc_data_structures;
extern crate serialize;
extern crate collections;
extern crate rustc_const_eval;
extern crate rustc_const_math;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
#[macro_use] #[no_link] extern crate rustc_bitflags;
@ -91,8 +91,7 @@ pub mod lint;
pub mod middle {
pub mod astconv_util;
pub mod expr_use_visitor; // STAGE0: increase glitch immunity
pub mod check_match;
pub mod const_eval;
pub mod const_val;
pub mod const_qualif;
pub mod cstore;
pub mod dataflow;

View File

@ -0,0 +1,101 @@
// Copyright 2012-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.
use syntax::parse::token::InternedString;
use syntax::ast;
use std::rc::Rc;
use middle::def_id::DefId;
use std::hash;
use std::mem::transmute;
use rustc_const_math::*;
use self::ConstVal::*;
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum ConstVal {
Float(f64),
Integral(ConstInt),
Str(InternedString),
ByteStr(Rc<Vec<u8>>),
Bool(bool),
Struct(ast::NodeId),
Tuple(ast::NodeId),
Function(DefId),
Array(ast::NodeId, u64),
Repeat(ast::NodeId, u64),
Char(char),
/// A value that only occurs in case `eval_const_expr` reported an error. You should never
/// handle this case. Its sole purpose is to allow more errors to be reported instead of
/// causing a fatal error.
Dummy,
}
impl hash::Hash for ConstVal {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
match *self {
Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
Integral(a) => a.hash(state),
Str(ref a) => a.hash(state),
ByteStr(ref a) => a.hash(state),
Bool(a) => a.hash(state),
Struct(a) => a.hash(state),
Tuple(a) => a.hash(state),
Function(a) => a.hash(state),
Array(a, n) => { a.hash(state); n.hash(state) },
Repeat(a, n) => { a.hash(state); n.hash(state) },
Char(c) => c.hash(state),
Dummy => ().hash(state),
}
}
}
/// Note that equality for `ConstVal` means that the it is the same
/// constant, not that the rust values are equal. In particular, `NaN
/// == NaN` (at least if it's the same NaN; distinct encodings for NaN
/// are considering unequal).
impl PartialEq for ConstVal {
fn eq(&self, other: &ConstVal) -> bool {
match (self, other) {
(&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
(&Integral(a), &Integral(b)) => a == b,
(&Str(ref a), &Str(ref b)) => a == b,
(&ByteStr(ref a), &ByteStr(ref b)) => a == b,
(&Bool(a), &Bool(b)) => a == b,
(&Struct(a), &Struct(b)) => a == b,
(&Tuple(a), &Tuple(b)) => a == b,
(&Function(a), &Function(b)) => a == b,
(&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
(&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
(&Char(a), &Char(b)) => a == b,
(&Dummy, &Dummy) => true, // FIXME: should this be false?
_ => false,
}
}
}
impl Eq for ConstVal { }
impl ConstVal {
pub fn description(&self) -> &'static str {
match *self {
Float(_) => "float",
Integral(i) => i.description(),
Str(_) => "string literal",
ByteStr(_) => "byte string literal",
Bool(_) => "boolean",
Struct(_) => "struct",
Tuple(_) => "tuple",
Function(_) => "function definition",
Array(..) => "array",
Repeat(..) => "repeat",
Char(..) => "char",
Dummy => "dummy value",
}
}
}

View File

@ -9,8 +9,8 @@
// except according to those terms.
use graphviz::IntoCow;
use middle::const_eval::ConstVal;
use rustc_const_eval::{ConstUsize, ConstInt};
use middle::const_val::ConstVal;
use rustc_const_math::{ConstUsize, ConstInt};
use middle::def_id::DefId;
use ty::subst::Substs;
use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
@ -999,7 +999,7 @@ impl<'tcx> Debug for Literal<'tcx> {
/// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
use middle::const_eval::ConstVal::*;
use middle::const_val::ConstVal::*;
match *const_val {
Float(f) => write!(fmt, "{:?}", f),
Integral(n) => write!(fmt, "{}", n),

View File

@ -8,12 +8,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use middle::const_eval::ConstVal;
use middle::const_val::ConstVal;
use middle::def_id::DefId;
use ty::subst::Substs;
use ty::{ClosureSubsts, FnOutput, Region, Ty};
use mir::repr::*;
use rustc_const_eval::ConstUsize;
use rustc_const_math::ConstUsize;
use rustc_data_structures::tuple_slice::TupleSlice;
use syntax::codemap::Span;

View File

@ -136,6 +136,7 @@ pub struct Options {
pub no_trans: bool,
pub error_format: ErrorOutputType,
pub treat_err_as_bug: bool,
pub continue_parse_after_error: bool,
pub mir_opt_level: usize,
/// if true, build up the dep-graph
@ -257,6 +258,7 @@ pub fn basic_options() -> Options {
parse_only: false,
no_trans: false,
treat_err_as_bug: false,
continue_parse_after_error: false,
mir_opt_level: 1,
build_dep_graph: false,
dump_dep_graph: false,
@ -631,6 +633,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"run all passes except translation; no output"),
treat_err_as_bug: bool = (false, parse_bool,
"treat all errors that occur as bugs"),
continue_parse_after_error: bool = (false, parse_bool,
"attempt to recover from parse errors (experimental)"),
incr_comp: bool = (false, parse_bool,
"enable incremental compilation (experimental)"),
dump_dep_graph: bool = (false, parse_bool,
@ -1045,6 +1049,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let parse_only = debugging_opts.parse_only;
let no_trans = debugging_opts.no_trans;
let treat_err_as_bug = debugging_opts.treat_err_as_bug;
let continue_parse_after_error = debugging_opts.continue_parse_after_error;
let mir_opt_level = debugging_opts.mir_opt_level.unwrap_or(1);
let incremental_compilation = debugging_opts.incr_comp;
let dump_dep_graph = debugging_opts.dump_dep_graph;
@ -1224,6 +1229,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
parse_only: parse_only,
no_trans: no_trans,
treat_err_as_bug: treat_err_as_bug,
continue_parse_after_error: continue_parse_after_error,
mir_opt_level: mir_opt_level,
build_dep_graph: incremental_compilation || dump_dep_graph,
dump_dep_graph: dump_dep_graph,

View File

@ -50,7 +50,7 @@ use syntax::attr::{self, AttrMetaMethods};
use syntax::codemap::{DUMMY_SP, Span};
use syntax::parse::token::InternedString;
use rustc_const_eval::ConstInt;
use rustc_const_math::ConstInt;
use rustc_front::hir;
use rustc_front::hir::{ItemImpl, ItemTrait, PatKind};

View File

@ -11,8 +11,6 @@
//! misc. type-system utilities too small to deserve their own file
use back::svh::Svh;
use middle::const_eval::{self, ConstVal, ErrKind};
use middle::const_eval::EvalHint::UncheckedExprHint;
use middle::def_id::DefId;
use ty::subst;
use infer;
@ -22,7 +20,7 @@ use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
use ty::{Disr, ParameterEnvironment};
use ty::TypeVariants::*;
use rustc_const_eval::{ConstInt, ConstIsize, ConstUsize};
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
use std::cmp;
use std::hash::{Hash, SipHasher, Hasher};
@ -269,41 +267,6 @@ impl<'tcx> TyCtxt<'tcx> {
(a, b)
}
/// Returns the repeat count for a repeating vector expression.
pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize {
let hint = UncheckedExprHint(self.types.usize);
match const_eval::eval_const_expr_partial(self, count_expr, hint, None) {
Ok(ConstVal::Integral(ConstInt::Usize(count))) => {
let val = count.as_u64(self.sess.target.uint_type);
assert_eq!(val as usize as u64, val);
val as usize
},
Ok(const_val) => {
span_err!(self.sess, count_expr.span, E0306,
"expected positive integer for repeat count, found {}",
const_val.description());
0
}
Err(err) => {
let err_msg = match count_expr.node {
hir::ExprPath(None, hir::Path {
global: false,
ref segments,
..
}) if segments.len() == 1 =>
format!("found variable"),
_ => match err.kind {
ErrKind::MiscCatchAll => format!("but found {}", err.description()),
_ => format!("but {}", err.description())
}
};
span_err!(self.sess, count_expr.span, E0307,
"expected constant integer for repeat count, {}", err_msg);
0
}
}
}
/// Given a set of predicates that apply to an object type, returns
/// the region bounds that the (erased) `Self` type must
/// outlive. Precisely *because* the `Self` type is erased, the

View File

@ -11,4 +11,9 @@ crate-type = ["dylib"]
[dependencies]
log = { path = "../liblog" }
serialize = { path = "../libserialize" }
rustc = { path = "../librustc" }
rustc_front = { path = "../librustc_front" }
rustc_back = { path = "../librustc_back" }
rustc_const_math = { path = "../librustc_const_math" }
syntax = { path = "../libsyntax" }
graphviz = { path = "../libgraphviz" }

View File

@ -1,4 +1,4 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -12,22 +12,22 @@ pub use self::Constructor::*;
use self::Usefulness::*;
use self::WitnessPreference::*;
use dep_graph::DepNode;
use middle::const_eval::{compare_const_vals, ConstVal};
use middle::const_eval::{eval_const_expr, eval_const_expr_partial};
use middle::const_eval::{const_expr_to_pat, lookup_const_by_id};
use middle::const_eval::EvalHint::ExprTypeChecked;
use middle::def::*;
use middle::def_id::{DefId};
use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
use middle::expr_use_visitor::{LoanCause, MutateMode};
use middle::expr_use_visitor as euv;
use infer;
use middle::mem_categorization::{cmt};
use middle::pat_util::*;
use traits::ProjectionMode;
use ty::*;
use ty;
use rustc::dep_graph::DepNode;
use rustc::middle::const_val::ConstVal;
use ::{eval_const_expr, eval_const_expr_partial, compare_const_vals};
use ::{const_expr_to_pat, lookup_const_by_id};
use ::EvalHint::ExprTypeChecked;
use rustc::middle::def::*;
use rustc::middle::def_id::{DefId};
use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
use rustc::middle::expr_use_visitor as euv;
use rustc::infer;
use rustc::middle::mem_categorization::{cmt};
use rustc::middle::pat_util::*;
use rustc::traits::ProjectionMode;
use rustc::ty::*;
use rustc::ty;
use std::cmp::Ordering;
use std::fmt;
use std::iter::{FromIterator, IntoIterator, repeat};
@ -44,7 +44,7 @@ use syntax::codemap::{Span, Spanned, DUMMY_SP};
use rustc_front::fold::{Folder, noop_fold_pat};
use rustc_front::print::pprust::pat_to_string;
use syntax::ptr::P;
use util::nodemap::FnvHashMap;
use rustc::util::nodemap::FnvHashMap;
pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
id: DUMMY_NODE_ID,
@ -546,7 +546,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
ty::TyTuple(_) => PatKind::Tup(pats.collect()),
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
let v = adt.variant_of_ctor(ctor);
let v = ctor.variant_for_adt(adt);
match v.kind() {
VariantKind::Struct => {
let field_pats: hir::HirVec<_> = v.fields.iter()
@ -617,13 +617,13 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
})
}
impl<'tcx, 'container> ty::AdtDefData<'tcx, 'container> {
fn variant_of_ctor(&self,
ctor: &Constructor)
-> &VariantDefData<'tcx, 'container> {
match ctor {
&Variant(vid) => self.variant_with_id(vid),
_ => self.struct_variant()
impl Constructor {
fn variant_for_adt<'tcx, 'container, 'a>(&self,
adt: &'a ty::AdtDefData<'tcx, 'container>)
-> &'a VariantDefData<'tcx, 'container> {
match self {
&Variant(vid) => adt.variant_with_id(vid),
_ => adt.struct_variant()
}
}
}
@ -843,7 +843,7 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us
_ => 1
},
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
adt.variant_of_ctor(ctor).fields.len()
ctor.variant_for_adt(adt).fields.len()
}
ty::TyArray(_, n) => n,
_ => 0
@ -924,7 +924,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
PatKind::Struct(_, ref pattern_fields, _) => {
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
let adt = cx.tcx.node_id_to_type(pat_id).ty_adt_def().unwrap();
let variant = adt.variant_of_ctor(constructor);
let variant = constructor.variant_for_adt(adt);
let def_variant = adt.variant_of_def(def);
if variant.did == def_variant.did {
Some(variant.fields.iter().map(|sf| {

View File

@ -0,0 +1,545 @@
// Copyright 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.
#![allow(non_snake_case)]
// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {
E0001: r##"
This error suggests that the expression arm corresponding to the noted pattern
will never be reached as for all possible values of the expression being
matched, one of the preceding patterns will match.
This means that perhaps some of the preceding patterns are too general, this
one is too specific or the ordering is incorrect.
For example, the following `match` block has too many arms:
```compile_fail
match foo {
Some(bar) => {/* ... */}
None => {/* ... */}
_ => {/* ... */} // All possible cases have already been handled
}
```
`match` blocks have their patterns matched in order, so, for example, putting
a wildcard arm above a more specific arm will make the latter arm irrelevant.
Ensure the ordering of the match arm is correct and remove any superfluous
arms.
"##,
E0002: r##"
This error indicates that an empty match expression is invalid because the type
it is matching on is non-empty (there exist values of this type). In safe code
it is impossible to create an instance of an empty type, so empty match
expressions are almost never desired. This error is typically fixed by adding
one or more cases to the match expression.
An example of an empty type is `enum Empty { }`. So, the following will work:
```
enum Empty {}
fn foo(x: Empty) {
match x {
// empty
}
}
```
However, this won't:
```compile_fail
enum Empty {}
fn foo(x: Option<String>) {
match x {
// empty
}
}
```
"##,
E0003: r##"
Not-a-Number (NaN) values cannot be compared for equality and hence can never
match the input to a match expression. So, the following will not compile:
```compile_fail
const NAN: f32 = 0.0 / 0.0;
let number = 0.1f32;
match number {
NAN => { /* ... */ },
_ => {}
}
```
To match against NaN values, you should instead use the `is_nan()` method in a
guard, like so:
```
let number = 0.1f32;
match number {
x if x.is_nan() => { /* ... */ }
_ => {}
}
```
"##,
E0004: r##"
This error indicates that the compiler cannot guarantee a matching pattern for
one or more possible inputs to a match expression. Guaranteed matches are
required in order to assign values to match expressions, or alternatively,
determine the flow of execution. Erroneous code example:
```compile_fail
enum Terminator {
HastaLaVistaBaby,
TalkToMyHand,
}
let x = Terminator::HastaLaVistaBaby;
match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered
Terminator::TalkToMyHand => {}
}
```
If you encounter this error you must alter your patterns so that every possible
value of the input type is matched. For types with a small number of variants
(like enums) you should probably cover all cases explicitly. Alternatively, the
underscore `_` wildcard pattern can be added after all other patterns to match
"anything else". Example:
```
enum Terminator {
HastaLaVistaBaby,
TalkToMyHand,
}
let x = Terminator::HastaLaVistaBaby;
match x {
Terminator::TalkToMyHand => {}
Terminator::HastaLaVistaBaby => {}
}
// or:
match x {
Terminator::TalkToMyHand => {}
_ => {}
}
```
"##,
E0005: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee
that a name will be extracted in all cases. Erroneous code example:
```compile_fail
let x = Some(1);
let Some(y) = x;
// error: refutable pattern in local binding: `None` not covered
```
If you encounter this error you probably need to use a `match` or `if let` to
deal with the possibility of failure. Example:
```compile_fail
let x = Some(1);
match x {
Some(y) => {
// do something
},
None => {}
}
// or:
if let Some(y) = x {
// do something
}
```
"##,
E0007: r##"
This error indicates that the bindings in a match arm would require a value to
be moved into more than one location, thus violating unique ownership. Code
like the following is invalid as it requires the entire `Option<String>` to be
moved into a variable called `op_string` while simultaneously requiring the
inner `String` to be moved into a variable called `s`.
```compile_fail
let x = Some("s".to_string());
match x {
op_string @ Some(s) => {},
None => {},
}
```
See also the error E0303.
"##,
E0008: r##"
Names bound in match arms retain their type in pattern guards. As such, if a
name is bound by move in a pattern, it should also be moved to wherever it is
referenced in the pattern guard code. Doing so however would prevent the name
from being available in the body of the match arm. Consider the following:
```compile_fail
match Some("hi".to_string()) {
Some(s) if s.len() == 0 => {}, // use s.
_ => {},
}
```
The variable `s` has type `String`, and its use in the guard is as a variable of
type `String`. The guard code effectively executes in a separate scope to the
body of the arm, so the value would be moved into this anonymous scope and
therefore become unavailable in the body of the arm. Although this example seems
innocuous, the problem is most clear when considering functions that take their
argument by value.
```compile_fail
match Some("hi".to_string()) {
Some(s) if { drop(s); false } => (),
Some(s) => {}, // use s.
_ => {},
}
```
The value would be dropped in the guard then become unavailable not only in the
body of that arm but also in all subsequent arms! The solution is to bind by
reference when using guards or refactor the entire expression, perhaps by
putting the condition inside the body of the arm.
"##,
E0009: r##"
In a pattern, all values that don't implement the `Copy` trait have to be bound
the same way. The goal here is to avoid binding simultaneously by-move and
by-ref.
This limitation may be removed in a future version of Rust.
Erroneous code example:
```compile_fail
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((y, ref z)) => {},
None => panic!()
}
```
You have two solutions:
Solution #1: Bind the pattern's values the same way.
```
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((ref y, ref z)) => {},
// or Some((y, z)) => {}
None => panic!()
}
```
Solution #2: Implement the `Copy` trait for the `X` structure.
However, please keep in mind that the first solution should be preferred.
```
#[derive(Clone, Copy)]
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((y, ref z)) => {},
None => panic!()
}
```
"##,
E0158: r##"
`const` and `static` mean different things. A `const` is a compile-time
constant, an alias for a literal value. This property means you can match it
directly within a pattern.
The `static` keyword, on the other hand, guarantees a fixed location in memory.
This does not always mean that the value is constant. For example, a global
mutex can be declared `static` as well.
If you want to match against a `static`, consider using a guard instead:
```
static FORTY_TWO: i32 = 42;
match Some(42) {
Some(x) if x == FORTY_TWO => {}
_ => {}
}
```
"##,
E0162: r##"
An if-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding instead. For instance:
```compile_fail
struct Irrefutable(i32);
let irr = Irrefutable(0);
// This fails to compile because the match is irrefutable.
if let Irrefutable(x) = irr {
// This body will always be executed.
foo(x);
}
```
Try this instead:
```ignore
struct Irrefutable(i32);
let irr = Irrefutable(0);
let Irrefutable(x) = irr;
foo(x);
```
"##,
E0165: r##"
A while-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding inside a `loop` instead. For instance:
```compile_fail
struct Irrefutable(i32);
let irr = Irrefutable(0);
// This fails to compile because the match is irrefutable.
while let Irrefutable(x) = irr {
...
}
Try this instead:
```
struct Irrefutable(i32);
let irr = Irrefutable(0);
loop {
let Irrefutable(x) = irr;
...
}
```
"##,
E0170: r##"
Enum variants are qualified by default. For example, given this type:
```
enum Method {
GET,
POST,
}
```
You would match it using:
```
enum Method {
GET,
POST,
}
let m = Method::GET;
match m {
Method::GET => {},
Method::POST => {},
}
```
If you don't qualify the names, the code will bind new variables named "GET" and
"POST" instead. This behavior is likely not what you want, so `rustc` warns when
that happens.
Qualified names are good practice, and most code works well with them. But if
you prefer them unqualified, you can import the variants into scope:
```ignore
use Method::*;
enum Method { GET, POST }
```
If you want others to be able to import variants from your module directly, use
`pub use`:
```ignore
pub use Method::*;
enum Method { GET, POST }
```
"##,
E0297: r##"
Patterns used to bind names must be irrefutable. That is, they must guarantee
that a name will be extracted in all cases. Instead of pattern matching the
loop variable, consider using a `match` or `if let` inside the loop body. For
instance:
```compile_fail
let xs : Vec<Option<i32>> = vec!(Some(1), None);
// This fails because `None` is not covered.
for Some(x) in xs {
// ...
}
```
Match inside the loop instead:
```
let xs : Vec<Option<i32>> = vec!(Some(1), None);
for item in xs {
match item {
Some(x) => {},
None => {},
}
}
```
Or use `if let`:
```
let xs : Vec<Option<i32>> = vec!(Some(1), None);
for item in xs {
if let Some(x) = item {
// ...
}
}
```
"##,
E0301: r##"
Mutable borrows are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if mutable
borrows were allowed:
```compile_fail
match Some(()) {
None => { },
option if option.take().is_none() => {
/* impossible, option is `Some` */
},
Some(_) => { } // When the previous match failed, the option became `None`.
}
```
"##,
E0302: r##"
Assignments are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if assignments
were allowed:
```compile_fail
match Some(()) {
None => { },
option if { option = None; false } { },
Some(_) => { } // When the previous match failed, the option became `None`.
}
```
"##,
E0303: r##"
In certain cases it is possible for sub-bindings to violate memory safety.
Updates to the borrow checker in a future version of Rust may remove this
restriction, but for now patterns must be rewritten without sub-bindings.
```ignore
// Before.
match Some("hi".to_string()) {
ref op_string_ref @ Some(s) => {},
None => {},
}
// After.
match Some("hi".to_string()) {
Some(ref s) => {
let op_string_ref = &Some(s);
// ...
},
None => {},
}
```
The `op_string_ref` binding has type `&Option<&String>` in both cases.
See also https://github.com/rust-lang/rust/issues/14587
"##,
E0306: r##"
In an array literal `[x; N]`, `N` is the number of elements in the array. This
must be an unsigned integer. Erroneous code example:
```compile_fail
let x = [0i32; true]; // error: expected positive integer for repeat count,
// found boolean
```
Working example:
```
let x = [0i32; 2];
```
"##,
E0307: r##"
The length of an array is part of its type. For this reason, this length must
be a compile-time constant. Erroneous code example:
```compile_fail
let len = 10;
let x = [0i32; len]; // error: expected constant integer for repeat count,
// found variable
```
"##,
}
register_diagnostics! {
E0298, // mismatched types between arms
E0299, // mismatched types between arms
E0471, // constant evaluation error: ..
}

View File

@ -1,4 +1,4 @@
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -10,23 +10,24 @@
//#![allow(non_camel_case_types)]
use self::ConstVal::*;
use rustc::middle::const_val::ConstVal::*;
use rustc::middle::const_val::ConstVal;
use self::ErrKind::*;
use self::EvalHint::*;
use front::map as ast_map;
use front::map::blocks::FnLikeNode;
use lint;
use middle::cstore::{self, CrateStore, InlinedItem};
use {infer, traits};
use middle::def::Def;
use middle::def_id::DefId;
use middle::pat_util::def_to_path;
use ty::{self, subst, Ty, TyCtxt};
use ty::util::IntTypeExt;
use traits::ProjectionMode;
use middle::astconv_util::ast_ty_to_prim_ty;
use util::nodemap::NodeMap;
use rustc::front::map as ast_map;
use rustc::front::map::blocks::FnLikeNode;
use rustc::middle::cstore::{self, CrateStore, InlinedItem};
use rustc::{infer, traits};
use rustc::middle::def::Def;
use rustc::middle::def_id::DefId;
use rustc::middle::pat_util::def_to_path;
use rustc::ty::{self, Ty, TyCtxt, subst};
use rustc::ty::util::IntTypeExt;
use rustc::traits::ProjectionMode;
use rustc::middle::astconv_util::ast_ty_to_prim_ty;
use rustc::util::nodemap::NodeMap;
use rustc::lint;
use graphviz::IntoCow;
use syntax::ast;
@ -34,7 +35,6 @@ use rustc_front::hir::{Expr, PatKind};
use rustc_front::hir;
use rustc_front::intravisit::FnKind;
use syntax::codemap::Span;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use syntax::codemap;
use syntax::attr::IntType;
@ -42,11 +42,8 @@ use syntax::attr::IntType;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::hash_map::Entry::Vacant;
use std::hash;
use std::mem::transmute;
use std::rc::Rc;
use rustc_const_eval::*;
use rustc_const_math::*;
macro_rules! math {
($e:expr, $op:expr) => {
@ -241,89 +238,6 @@ pub fn lookup_const_fn_by_id<'tcx>(tcx: &TyCtxt<'tcx>, def_id: DefId)
}
}
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum ConstVal {
Float(f64),
Integral(ConstInt),
Str(InternedString),
ByteStr(Rc<Vec<u8>>),
Bool(bool),
Struct(ast::NodeId),
Tuple(ast::NodeId),
Function(DefId),
Array(ast::NodeId, u64),
Repeat(ast::NodeId, u64),
Char(char),
/// A value that only occurs in case `eval_const_expr` reported an error. You should never
/// handle this case. Its sole purpose is to allow more errors to be reported instead of
/// causing a fatal error.
Dummy,
}
impl hash::Hash for ConstVal {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
match *self {
Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
Integral(a) => a.hash(state),
Str(ref a) => a.hash(state),
ByteStr(ref a) => a.hash(state),
Bool(a) => a.hash(state),
Struct(a) => a.hash(state),
Tuple(a) => a.hash(state),
Function(a) => a.hash(state),
Array(a, n) => { a.hash(state); n.hash(state) },
Repeat(a, n) => { a.hash(state); n.hash(state) },
Char(c) => c.hash(state),
Dummy => ().hash(state),
}
}
}
/// Note that equality for `ConstVal` means that the it is the same
/// constant, not that the rust values are equal. In particular, `NaN
/// == NaN` (at least if it's the same NaN; distinct encodings for NaN
/// are considering unequal).
impl PartialEq for ConstVal {
fn eq(&self, other: &ConstVal) -> bool {
match (self, other) {
(&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
(&Integral(a), &Integral(b)) => a == b,
(&Str(ref a), &Str(ref b)) => a == b,
(&ByteStr(ref a), &ByteStr(ref b)) => a == b,
(&Bool(a), &Bool(b)) => a == b,
(&Struct(a), &Struct(b)) => a == b,
(&Tuple(a), &Tuple(b)) => a == b,
(&Function(a), &Function(b)) => a == b,
(&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
(&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
(&Char(a), &Char(b)) => a == b,
(&Dummy, &Dummy) => true, // FIXME: should this be false?
_ => false,
}
}
}
impl Eq for ConstVal { }
impl ConstVal {
pub fn description(&self) -> &'static str {
match *self {
Float(_) => "float",
Integral(i) => i.description(),
Str(_) => "string literal",
ByteStr(_) => "byte string literal",
Bool(_) => "boolean",
Struct(_) => "struct",
Tuple(_) => "tuple",
Function(_) => "function definition",
Array(..) => "array",
Repeat(..) => "repeat",
Char(..) => "char",
Dummy => "dummy value",
}
}
}
pub fn const_expr_to_pat(tcx: &ty::TyCtxt, expr: &Expr, pat_id: ast::NodeId, span: Span)
-> Result<P<hir::Pat>, DefId> {
let pat_ty = tcx.expr_ty(expr);
@ -352,7 +266,6 @@ pub fn const_expr_to_pat(tcx: &ty::TyCtxt, expr: &Expr, pat_id: ast::NodeId, spa
}
_ => { }
}
let pat = match expr.node {
hir::ExprTup(ref exprs) =>
PatKind::Tup(try!(exprs.iter()
@ -1275,3 +1188,39 @@ pub fn compare_lit_exprs<'tcx>(tcx: &TyCtxt<'tcx>,
};
compare_const_vals(&a, &b)
}
/// Returns the repeat count for a repeating vector expression.
pub fn eval_repeat_count(tcx: &TyCtxt, count_expr: &hir::Expr) -> usize {
let hint = UncheckedExprHint(tcx.types.usize);
match eval_const_expr_partial(tcx, count_expr, hint, None) {
Ok(Integral(Usize(count))) => {
let val = count.as_u64(tcx.sess.target.uint_type);
assert_eq!(val as usize as u64, val);
val as usize
},
Ok(const_val) => {
span_err!(tcx.sess, count_expr.span, E0306,
"expected positive integer for repeat count, found {}",
const_val.description());
0
}
Err(err) => {
let err_msg = match count_expr.node {
hir::ExprPath(None, hir::Path {
global: false,
ref segments,
..
}) if segments.len() == 1 =>
format!("found variable"),
_ => match err.kind {
MiscCatchAll => format!("but found {}", err.description()),
_ => format!("but {}", err.description())
}
};
span_err!(tcx.sess, count_expr.span, E0307,
"expected constant integer for repeat count, {}", err_msg);
0
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// 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.
//
@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Rusty Mathematics
//! constant evaluation on the HIR and code to validate patterns/matches
//!
//! # Note
//!
@ -25,19 +25,29 @@
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_patterns)]
#![feature(iter_arith)]
#![feature(question_mark)]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
#[macro_use] extern crate log;
extern crate rustc;
extern crate rustc_front;
extern crate rustc_back;
extern crate rustc_const_math;
extern crate graphviz;
extern crate serialize as rustc_serialize; // used by deriving
mod int;
mod us;
mod is;
mod err;
// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;
pub use int::*;
pub use us::*;
pub use is::*;
pub use err::ConstMathErr;
mod eval;
pub mod check_match;
pub use eval::*;
// Build the diagnostics array at the end so that the metadata includes error use sites.
__build_diagnostic_array! { librustc_const_eval, DIAGNOSTICS }

View File

@ -0,0 +1,14 @@
[package]
authors = ["The Rust Project Developers"]
name = "rustc_const_math"
version = "0.0.0"
[lib]
name = "rustc_const_math"
path = "lib.rs"
crate-type = ["dylib"]
[dependencies]
log = { path = "../liblog" }
serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }

View File

@ -326,7 +326,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 try!(self.infer(rhs)) {
match self.infer(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),
@ -353,7 +353,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 try!(self.infer(rhs)) {
match self.infer(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))),

View File

@ -0,0 +1,43 @@
// Copyright 2012-2013 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.
//! Rusty Mathematics
//!
//! # Note
//!
//! This API is completely unstable and subject to change.
#![crate_name = "rustc_const_math"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![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/")]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(question_mark)]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate serialize as rustc_serialize; // used by deriving
mod int;
mod us;
mod is;
mod err;
pub use int::*;
pub use us::*;
pub use is::*;
pub use err::ConstMathErr;

View File

@ -17,6 +17,7 @@ log = { path = "../liblog" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_borrowck = { path = "../librustc_borrowck" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_front = { path = "../librustc_front" }
rustc_lint = { path = "../librustc_lint" }
rustc_llvm = { path = "../librustc_llvm" }

View File

@ -38,6 +38,7 @@ use rustc_plugin as plugin;
use rustc_front::hir;
use rustc_front::lowering::{lower_crate, LoweringContext};
use rustc_passes::{no_asm, loops, consts, const_fn, rvalues, static_recursion};
use rustc_const_eval::check_match;
use super::Compilation;
use serialize::json;
@ -428,6 +429,8 @@ pub fn phase_1_parse_input<'a>(sess: &'a Session,
// memory, but they do not restore the initial state.
syntax::ext::mtwt::reset_tables();
token::reset_ident_interner();
let continue_after_error = sess.opts.continue_parse_after_error;
sess.diagnostic().set_continue_after_error(continue_after_error);
let krate = time(sess.time_passes(), "parsing", || {
match *input {
@ -443,6 +446,8 @@ pub fn phase_1_parse_input<'a>(sess: &'a Session,
}
})?;
sess.diagnostic().set_continue_after_error(true);
if sess.opts.debugging_opts.ast_json_noexpand {
println!("{}", json::as_json(&krate));
}
@ -851,7 +856,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
time(time_passes,
"match checking",
|| middle::check_match::check_crate(tcx));
|| check_match::check_crate(tcx));
// this must run before MIR dump, because
// "not all control paths return a value" is reported here.

View File

@ -40,6 +40,7 @@ extern crate libc;
extern crate rustc;
extern crate rustc_back;
extern crate rustc_borrowck;
extern crate rustc_const_eval;
extern crate rustc_passes;
extern crate rustc_front;
extern crate rustc_lint;
@ -1090,6 +1091,7 @@ pub fn diagnostics_registry() -> diagnostics::registry::Registry {
all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
Registry::new(&all_errors)
}

View File

@ -12,5 +12,6 @@ crate-type = ["dylib"]
log = { path = "../liblog" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_front = { path = "../librustc_front" }
syntax = { path = "../libsyntax" }

View File

@ -46,6 +46,7 @@ extern crate rustc;
extern crate log;
extern crate rustc_front;
extern crate rustc_back;
extern crate rustc_const_eval;
pub use rustc::lint as lint;
pub use rustc::middle as middle;

View File

@ -14,8 +14,9 @@ use middle::def_id::DefId;
use rustc::infer;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
use middle::const_eval::{eval_const_expr_partial, ConstVal};
use middle::const_eval::EvalHint::ExprTypeChecked;
use middle::const_val::ConstVal;
use rustc_const_eval::eval_const_expr_partial;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use util::nodemap::{FnvHashSet};
use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass};

View File

@ -15,7 +15,7 @@ rbml = { path = "../librbml" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_bitflags = { path = "../librustc_bitflags" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_front = { path = "../librustc_front" }
rustc_llvm = { path = "../librustc_llvm" }
serialize = { path = "../libserialize" }

View File

@ -36,7 +36,7 @@ use rustc::ty::subst;
use rustc::ty::{ImplContainer, TraitContainer};
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind};
use rustc_const_eval::ConstInt;
use rustc_const_math::ConstInt;
use rustc::mir;
use rustc::mir::visit::MutVisitor;

View File

@ -37,7 +37,7 @@ extern crate rustc;
extern crate rustc_back;
extern crate rustc_front;
extern crate rustc_llvm;
extern crate rustc_const_eval;
extern crate rustc_const_math;
pub use rustc::middle;

View File

@ -14,6 +14,7 @@ log = { path = "../liblog" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_front = { path = "../librustc_front" }
syntax = { path = "../libsyntax" }

View File

@ -15,7 +15,7 @@
use build::{BlockAnd, BlockAndExtension, Builder};
use rustc_data_structures::fnv::FnvHashMap;
use rustc::middle::const_eval::ConstVal;
use rustc::middle::const_val::ConstVal;
use rustc::ty::{AdtDef, Ty};
use rustc::mir::repr::*;
use hair::*;

View File

@ -19,7 +19,7 @@ use build::Builder;
use build::matches::{Candidate, MatchPair, Test, TestKind};
use hair::*;
use rustc_data_structures::fnv::FnvHashMap;
use rustc::middle::const_eval::ConstVal;
use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, Ty};
use rustc::mir::repr::*;
use syntax::codemap::Span;

View File

@ -94,8 +94,8 @@ use rustc::ty::{self, Ty, TyCtxt};
use rustc::mir::repr::*;
use syntax::codemap::{Span, DUMMY_SP};
use syntax::parse::token::intern_and_get_ident;
use rustc::middle::const_eval::ConstVal;
use rustc_const_eval::ConstInt;
use rustc::middle::const_val::ConstVal;
use rustc_const_math::ConstInt;
pub struct Scope<'tcx> {
/// the scope-id within the scope_datas

View File

@ -10,13 +10,14 @@
use hair::*;
use rustc_data_structures::fnv::FnvHashMap;
use rustc_const_eval::ConstInt;
use rustc_const_math::ConstInt;
use hair::cx::Cx;
use hair::cx::block;
use hair::cx::to_ref::ToRef;
use rustc::front::map;
use rustc::middle::def::Def;
use rustc::middle::const_eval::{self, ConstVal};
use rustc::middle::const_val::ConstVal;
use rustc_const_eval as const_eval;
use rustc::middle::region::CodeExtent;
use rustc::middle::pat_util;
use rustc::ty::{self, VariantDef, Ty};

View File

@ -18,7 +18,8 @@
use hair::*;
use rustc::mir::repr::*;
use rustc::middle::const_eval::{self, ConstVal};
use rustc::middle::const_val::ConstVal;
use rustc_const_eval as const_eval;
use rustc::middle::def_id::DefId;
use rustc::infer::InferCtxt;
use rustc::ty::subst::{Subst, Substs};
@ -26,7 +27,7 @@ use rustc::ty::{self, Ty, TyCtxt};
use syntax::codemap::Span;
use syntax::parse::token;
use rustc_front::hir;
use rustc_const_eval::{ConstInt, ConstUsize};
use rustc_const_math::{ConstInt, ConstUsize};
#[derive(Copy, Clone)]
pub struct Cx<'a, 'tcx: 'a> {

View File

@ -11,7 +11,7 @@
use hair::*;
use hair::cx::Cx;
use rustc_data_structures::fnv::FnvHashMap;
use rustc::middle::const_eval;
use rustc_const_eval as const_eval;
use rustc::middle::def::Def;
use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
use rustc::ty::{self, Ty};

View File

@ -16,7 +16,7 @@
use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp,
TypedConstVal};
use rustc::middle::const_eval::ConstVal;
use rustc::middle::const_val::ConstVal;
use rustc::middle::def_id::DefId;
use rustc::middle::region::CodeExtent;
use rustc::ty::subst::Substs;

View File

@ -32,6 +32,7 @@ extern crate rustc_data_structures;
extern crate rustc_front;
extern crate rustc_back;
extern crate syntax;
extern crate rustc_const_math;
extern crate rustc_const_eval;
pub mod build;

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::middle::const_eval::ConstVal;
use rustc::middle::const_val::ConstVal;
use rustc::ty::TyCtxt;
use rustc::mir::repr::*;
use rustc::mir::transform::{MirPass, Pass};

View File

@ -11,5 +11,6 @@ crate-type = ["dylib"]
[dependencies]
log = { path = "../liblog" }
rustc = { path = "../librustc" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_front = { path = "../librustc_front" }
syntax = { path = "../libsyntax" }

View File

@ -26,9 +26,10 @@
use rustc::dep_graph::DepNode;
use rustc::ty::cast::{CastKind};
use rustc::middle::const_eval::{self, ConstEvalErr};
use rustc::middle::const_eval::ErrKind::IndexOpFeatureGated;
use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs};
use rustc_const_eval::{eval_const_expr_partial, lookup_const_by_id};
use rustc_const_eval::ErrKind::IndexOpFeatureGated;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc::middle::def::Def;
use rustc::middle::def_id::DefId;
use rustc::middle::expr_use_visitor as euv;
@ -169,7 +170,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
def_id: DefId,
ret_ty: Ty<'tcx>)
-> bool {
if let Some(fn_like) = const_eval::lookup_const_fn_by_id(self.tcx, def_id) {
if let Some(fn_like) = lookup_const_fn_by_id(self.tcx, def_id) {
if
// we are in a static/const initializer
self.mode != Mode::Var &&
@ -335,7 +336,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
self.global_expr(Mode::Const, &start);
self.global_expr(Mode::Const, &end);
match const_eval::compare_lit_exprs(self.tcx, start, end) {
match compare_lit_exprs(self.tcx, start, end) {
Some(Ordering::Less) |
Some(Ordering::Equal) => {}
Some(Ordering::Greater) => {
@ -431,7 +432,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
match node_ty.sty {
ty::TyUint(_) | ty::TyInt(_) if div_or_rem => {
if !self.qualif.intersects(ConstQualif::NOT_CONST) {
match const_eval::eval_const_expr_partial(
match eval_const_expr_partial(
self.tcx, ex, ExprTypeChecked, None) {
Ok(_) => {}
Err(ConstEvalErr { kind: IndexOpFeatureGated, ..}) => {},
@ -611,7 +612,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
Some(Def::Const(did)) |
Some(Def::AssociatedConst(did)) => {
let substs = Some(v.tcx.node_id_item_substs(e.id).substs);
if let Some((expr, _)) = const_eval::lookup_const_by_id(v.tcx, did, substs) {
if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) {
let inner = v.global_expr(Mode::Const, expr);
v.add_qualif(inner);
}

View File

@ -30,6 +30,7 @@
extern crate core;
extern crate rustc;
extern crate rustc_front;
extern crate rustc_const_eval;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;

View File

@ -17,6 +17,7 @@ log = { path = "../liblog" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_front = { path = "../librustc_front" }
rustc_llvm = { path = "../librustc_llvm" }

View File

@ -189,9 +189,8 @@ use self::Opt::*;
use self::FailureHandler::*;
use llvm::{ValueRef, BasicBlockRef};
use middle::check_match::StaticInliner;
use middle::check_match;
use middle::const_eval;
use rustc_const_eval::check_match::{self, StaticInliner};
use rustc_const_eval::{compare_lit_exprs, eval_const_expr};
use middle::def::{Def, DefMap};
use middle::def_id::DefId;
use middle::expr_use_visitor as euv;
@ -241,7 +240,7 @@ struct ConstantExpr<'a>(&'a hir::Expr);
impl<'a> ConstantExpr<'a> {
fn eq(self, other: ConstantExpr<'a>, tcx: &TyCtxt) -> bool {
match const_eval::compare_lit_exprs(tcx, self.0, other.0) {
match compare_lit_exprs(tcx, self.0, other.0) {
Some(result) => result == Ordering::Equal,
None => panic!("compare_list_exprs: type mismatch"),
}
@ -611,11 +610,11 @@ fn enter_opt<'a, 'p, 'blk, 'tcx>(
let ctor = match opt {
&ConstantValue(ConstantExpr(expr), _) => check_match::ConstantValue(
const_eval::eval_const_expr(bcx.tcx(), &expr)
eval_const_expr(bcx.tcx(), &expr)
),
&ConstantRange(ConstantExpr(lo), ConstantExpr(hi), _) => check_match::ConstantRange(
const_eval::eval_const_expr(bcx.tcx(), &lo),
const_eval::eval_const_expr(bcx.tcx(), &hi)
eval_const_expr(bcx.tcx(), &lo),
eval_const_expr(bcx.tcx(), &hi)
),
&SliceLengthEqual(n, _) =>
check_match::Slice(n),

View File

@ -13,7 +13,8 @@ use llvm;
use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
use llvm::{InternalLinkage, ValueRef, Bool, True};
use middle::const_qualif::ConstQualif;
use middle::const_eval::{self, ConstEvalErr};
use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind};
use rustc_const_eval::eval_repeat_count;
use middle::def::Def;
use middle::def_id::DefId;
use rustc::front::map as hir_map;
@ -38,7 +39,7 @@ use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::cast::{CastTy,IntTy};
use util::nodemap::NodeMap;
use rustc_const_eval::{ConstInt, ConstMathErr, ConstUsize, ConstIsize};
use rustc_const_math::{ConstInt, ConstMathErr, ConstUsize, ConstIsize};
use rustc_front::hir;
@ -197,7 +198,7 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
arg_vals: &[ValueRef],
param_substs: &'tcx Substs<'tcx>,
trueconst: TrueConst) -> Result<ValueRef, ConstEvalFailure> {
let fn_like = const_eval::lookup_const_fn_by_id(ccx.tcx(), def_id);
let fn_like = lookup_const_fn_by_id(ccx.tcx(), def_id);
let fn_like = fn_like.expect("lookup_const_fn_by_id failed in const_fn_call");
let body = match fn_like.body().expr {
@ -228,7 +229,7 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let substs = monomorphize::apply_param_substs(ccx.tcx(),
param_substs,
&substs.erase_regions());
match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(substs)) {
match lookup_const_by_id(ccx.tcx(), def_id, Some(substs)) {
Some((ref expr, _ty)) => expr,
None => {
ccx.sess().span_bug(ref_expr.span, "constant item not found")
@ -534,12 +535,12 @@ fn const_err(cx: &CrateContext,
Ok(())
},
(Err(err), TrueConst::Yes) => {
let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) };
let err = ConstEvalErr{ span: e.span, kind: ErrKind::Math(err) };
cx.tcx().sess.span_err(e.span, &err.description());
Err(Compiletime(err))
},
(Err(err), TrueConst::No) => {
let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) };
let err = ConstEvalErr{ span: e.span, kind: ErrKind::Math(err) };
cx.tcx().sess.span_warn(e.span, &err.description());
Err(Runtime(err))
},
@ -883,7 +884,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
hir::ExprRepeat(ref elem, ref count) => {
let unit_ty = ety.sequence_element_type(cx.tcx());
let llunitty = type_of::type_of(cx, unit_ty);
let n = cx.tcx().eval_repeat_count(count);
let n = eval_repeat_count(cx.tcx(), count);
let unit_val = const_expr(cx, &elem, param_substs, fn_args, trueconst)?.0;
let vs = vec![unit_val; n];
if val_ty(unit_val) != llunitty {

View File

@ -51,6 +51,7 @@ pub extern crate rustc_llvm as llvm;
extern crate rustc_mir;
extern crate rustc_platform_intrinsics as intrinsics;
extern crate serialize;
extern crate rustc_const_math;
extern crate rustc_const_eval;
#[macro_use] extern crate log;

View File

@ -10,8 +10,9 @@
use llvm::ValueRef;
use rustc::ty::{Ty, TypeFoldable};
use rustc::middle::const_eval::{self, ConstVal};
use rustc_const_eval::ConstInt::*;
use rustc::middle::const_val::ConstVal;
use rustc_const_math::ConstInt::*;
use rustc_const_eval::lookup_const_by_id;
use rustc::mir::repr as mir;
use abi;
use common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral,
@ -114,7 +115,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
let substs = Some(bcx.monomorphize(substs));
let expr = const_eval::lookup_const_by_id(bcx.tcx(), def_id, substs)
let expr = lookup_const_by_id(bcx.tcx(), def_id, substs)
.expect("def was const, but lookup_const_by_id failed").0;
// FIXME: this is falling back to translating from HIR. This is not easy to fix,
// because we would have somehow adapt const_eval to work on MIR rather than HIR.

View File

@ -11,8 +11,8 @@
use llvm::ValueRef;
use rustc::ty::{self, Ty};
use rustc::ty::cast::{CastTy, IntTy};
use middle::const_eval::ConstVal;
use rustc_const_eval::ConstInt;
use middle::const_val::ConstVal;
use rustc_const_math::ConstInt;
use rustc::mir::repr as mir;
use asm;

View File

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

View File

@ -16,5 +16,6 @@ fmt_macros = { path = "../libfmt_macros" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_front = { path = "../librustc_front" }
rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }

View File

@ -49,8 +49,9 @@
//! an rptr (`&r.T`) use the region `r` that appears in the rptr.
use middle::astconv_util::{prim_ty_to_ty, prohibit_type_params, prohibit_projection};
use middle::const_eval::{self, ConstVal};
use middle::const_eval::EvalHint::UncheckedExprHint;
use middle::const_val::ConstVal;
use rustc_const_eval::eval_const_expr_partial;
use rustc_const_eval::EvalHint::UncheckedExprHint;
use middle::def::{self, Def};
use middle::def_id::DefId;
use middle::resolve_lifetime as rl;
@ -65,7 +66,7 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::FnvHashSet;
use rustc_const_eval::ConstInt;
use rustc_const_math::ConstInt;
use syntax::{abi, ast};
use syntax::codemap::{Span, Pos};
@ -1681,7 +1682,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
}
hir::TyFixedLengthVec(ref ty, ref e) => {
let hint = UncheckedExprHint(tcx.types.usize);
match const_eval::eval_const_expr_partial(tcx, &e, hint, None) {
match eval_const_expr_partial(tcx, &e, hint, None) {
Ok(ConstVal::Integral(ConstInt::Usize(i))) => {
let i = i.as_u64(tcx.sess.target.uint_type);
assert_eq!(i as usize as u64, i);

View File

@ -130,6 +130,7 @@ use rustc_front::hir;
use rustc_front::hir::{Visibility, PatKind};
use rustc_front::print::pprust;
use rustc_back::slice;
use rustc_const_eval::eval_repeat_count;
mod assoc;
pub mod dropck;
@ -3592,7 +3593,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
}
hir::ExprRepeat(ref element, ref count_expr) => {
check_expr_has_type(fcx, &count_expr, tcx.types.usize);
let count = fcx.tcx().eval_repeat_count(&count_expr);
let count = eval_repeat_count(fcx.tcx(), &count_expr);
let uty = match expected {
ExpectHasType(uty) => {

View File

@ -66,8 +66,9 @@ use constrained_type_params as ctp;
use coherence;
use middle::lang_items::SizedTraitLangItem;
use middle::resolve_lifetime;
use middle::const_eval::{self, ConstVal};
use middle::const_eval::EvalHint::UncheckedExprHint;
use middle::const_val::ConstVal;
use rustc_const_eval::EvalHint::UncheckedExprHint;
use rustc_const_eval::eval_const_expr_partial;
use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme};
@ -81,7 +82,7 @@ use util::common::{ErrorReported, MemoizationMap};
use util::nodemap::{FnvHashMap, FnvHashSet};
use write_ty_to_tcx;
use rustc_const_eval::ConstInt;
use rustc_const_math::ConstInt;
use std::cell::RefCell;
use std::collections::HashSet;
@ -1045,7 +1046,7 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
let ty_hint = repr_ty.to_ty(tcx);
let hint = UncheckedExprHint(ty_hint);
match const_eval::eval_const_expr_partial(tcx, e, hint, None) {
match eval_const_expr_partial(tcx, e, hint, None) {
Ok(ConstVal::Integral(i)) => {
// FIXME: eval_const_expr_partial should return an error if the hint is wrong
match (repr_ty, i) {

View File

@ -92,6 +92,7 @@ extern crate rustc;
extern crate rustc_platform_intrinsics as intrinsics;
extern crate rustc_front;
extern crate rustc_back;
extern crate rustc_const_math;
extern crate rustc_const_eval;
pub use rustc::dep_graph;

View File

@ -14,6 +14,7 @@ arena = { path = "../libarena" }
getopts = { path = "../libgetopts" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_driver = { path = "../librustc_driver" }
rustc_front = { path = "../librustc_front" }
rustc_lint = { path = "../librustc_lint" }

View File

@ -22,7 +22,8 @@ use rustc::middle::def_id::DefId;
use rustc::ty::{self, TyCtxt};
use rustc::ty::subst;
use rustc::middle::stability;
use rustc::middle::const_eval;
use rustc_const_eval::lookup_const_by_id;
use core::DocContext;
use doctree;
@ -336,7 +337,7 @@ pub fn build_impl(cx: &DocContext,
let did = assoc_const.def_id;
let type_scheme = tcx.lookup_item_type(did);
let default = if assoc_const.has_value {
Some(const_eval::lookup_const_by_id(tcx, did, None)
Some(lookup_const_by_id(tcx, did, None)
.unwrap().0.span.to_src(cx))
} else {
None
@ -483,10 +484,9 @@ fn build_module(cx: &DocContext, tcx: &TyCtxt,
fn build_const(cx: &DocContext, tcx: &TyCtxt,
did: DefId) -> clean::Constant {
use rustc::middle::const_eval;
use rustc_front::print::pprust;
let (expr, ty) = const_eval::lookup_const_by_id(tcx, did, None).unwrap_or_else(|| {
let (expr, ty) = lookup_const_by_id(tcx, did, None).unwrap_or_else(|| {
panic!("expected lookup_const_by_id to succeed for {:?}", did);
});
debug!("converting constant expr {:?} to snippet", expr);

View File

@ -35,6 +35,7 @@ extern crate arena;
extern crate getopts;
extern crate libc;
extern crate rustc;
extern crate rustc_const_eval;
extern crate rustc_trans;
extern crate rustc_driver;
extern crate rustc_resolve;

View File

@ -837,8 +837,6 @@ impl<K, V, S> HashMap<K, V, S>
#[stable(feature = "rust1", since = "1.0.0")]
pub fn keys<'a>(&'a self) -> Keys<'a, K, V> {
fn first<A, B>((a, _): (A, B)) -> A { a }
let first: fn((&'a K,&'a V)) -> &'a K = first; // coerce to fn ptr
Keys { inner: self.iter().map(first) }
}
@ -862,8 +860,6 @@ impl<K, V, S> HashMap<K, V, S>
#[stable(feature = "rust1", since = "1.0.0")]
pub fn values<'a>(&'a self) -> Values<'a, K, V> {
fn second<A, B>((_, b): (A, B)) -> B { b }
let second: fn((&'a K,&'a V)) -> &'a V = second; // coerce to fn ptr
Values { inner: self.iter().map(second) }
}
@ -997,8 +993,6 @@ impl<K, V, S> HashMap<K, V, S>
#[stable(feature = "drain", since = "1.6.0")]
pub fn drain(&mut self) -> Drain<K, V> {
fn last_two<A, B, C>((_, b, c): (A, B, C)) -> (B, C) { (b, c) }
let last_two: fn((SafeHash, K, V)) -> (K, V) = last_two; // coerce to fn pointer
Drain {
inner: self.table.drain().map(last_two),
}
@ -1404,8 +1398,6 @@ impl<K, V, S> IntoIterator for HashMap<K, V, S>
/// ```
fn into_iter(self) -> IntoIter<K, V> {
fn last_two<A, B, C>((_, b, c): (A, B, C)) -> (B, C) { (b, c) }
let last_two: fn((SafeHash, K, V)) -> (K, V) = last_two;
IntoIter {
inner: self.table.into_iter().map(last_two)
}

View File

@ -415,8 +415,6 @@ impl<T, S> HashSet<T, S>
#[stable(feature = "drain", since = "1.6.0")]
pub fn drain(&mut self) -> Drain<T> {
fn first<A, B>((a, _): (A, B)) -> A { a }
let first: fn((T, ())) -> T = first; // coerce to fn pointer
Drain { iter: self.map.drain().map(first) }
}
@ -892,8 +890,6 @@ impl<T, S> IntoIterator for HashSet<T, S>
/// ```
fn into_iter(self) -> IntoIter<T> {
fn first<A, B>((a, _): (A, B)) -> A { a }
let first: fn((T, ())) -> T = first;
IntoIter { iter: self.map.into_iter().map(first) }
}
}

View File

@ -370,6 +370,7 @@ pub struct Handler {
emit: RefCell<Box<Emitter>>,
pub can_emit_warnings: bool,
treat_err_as_bug: bool,
continue_after_error: Cell<bool>,
delayed_span_bug: RefCell<Option<(MultiSpan, String)>>,
}
@ -392,10 +393,15 @@ impl Handler {
emit: RefCell::new(e),
can_emit_warnings: can_emit_warnings,
treat_err_as_bug: treat_err_as_bug,
continue_after_error: Cell::new(true),
delayed_span_bug: RefCell::new(None),
}
}
pub fn set_continue_after_error(&self, continue_after_error: bool) {
self.continue_after_error.set(continue_after_error);
}
pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
DiagnosticBuilder::new(&self.emit, Level::Cancelled, "")
}
@ -612,6 +618,7 @@ impl Handler {
lvl: Level) {
if lvl == Warning && !self.can_emit_warnings { return }
self.emit.borrow_mut().emit(msp, msg, None, lvl);
if !self.continue_after_error.get() { self.abort_if_errors(); }
}
pub fn emit_with_code(&self,
msp: Option<&MultiSpan>,
@ -620,10 +627,12 @@ impl Handler {
lvl: Level) {
if lvl == Warning && !self.can_emit_warnings { return }
self.emit.borrow_mut().emit(msp, msg, Some(code), lvl);
if !self.continue_after_error.get() { self.abort_if_errors(); }
}
pub fn custom_emit(&self, rsp: RenderSpan, msg: &str, lvl: Level) {
if lvl == Warning && !self.can_emit_warnings { return }
self.emit.borrow_mut().custom_emit(&rsp, msg, lvl);
if !self.continue_after_error.get() { self.abort_if_errors(); }
}
}

View File

@ -16,15 +16,15 @@
#[macro_use] extern crate rustc;
extern crate rustc_front;
extern crate rustc_plugin;
extern crate rustc_const_eval;
extern crate rustc_const_math;
extern crate syntax;
use rustc::mir::transform::{self, MirPass};
use rustc::mir::repr::{Mir, Literal};
use rustc::mir::visit::MutVisitor;
use rustc::ty;
use rustc::middle::const_eval::ConstVal;
use rustc_const_eval::ConstInt;
use rustc::middle::const_val::ConstVal;
use rustc_const_math::ConstInt;
use rustc_plugin::Registry;
use syntax::ast::NodeId;

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z continue-parse-after-error
// For style and consistency reasons, non-parametrized enum variants must
// be used simply as `ident` instead of `ident ()`.
// This test-case covers enum matching.

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z continue-parse-after-error
enum bird {
pub duck,
//~^ ERROR: expected identifier, found keyword `pub`

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z continue-parse-after-error
macro_rules! parallel {
(
// If future has `pred`/`moelarry` fragments (where "pred" is

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z continue-parse-after-error
macro_rules! ignored_item {
() => {
fn foo() {}

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z continue-parse-after-error
// Test that the parser is error correcting missing idents. Despite a parsing
// error (or two), we still run type checking (and don't get extra errors there).

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z continue-parse-after-error
// Test that we can recover from missing braces in the parser.
trait Foo {

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z continue-parse-after-error
// Test that we can recover from mismatched braces in the parser.
trait Foo {

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z continue-parse-after-error
struct Self;
//~^ ERROR expected identifier, found keyword `Self`

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
// compile-flags: -Z parse-only -Z continue-parse-after-error
fn main() {
let x = "\x80"; //~ ERROR may only be used

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
// compile-flags: -Z parse-only -Z continue-parse-after-error
// ignore-tidy-cr
// ignore-tidy-tab

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
// compile-flags: -Z parse-only -Z continue-parse-after-error
extern

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
// compile-flags: -Z parse-only -Z continue-parse-after-error
// ignore-tidy-tab

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
// compile-flags: -Z parse-only -Z continue-parse-after-error
// ignore-tidy-tab

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
// compile-flags: -Z parse-only -Z continue-parse-after-error
trait Serializable<'self, T> { //~ ERROR no longer a special lifetime

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only -Z continue-parse-after-error
fn main() {
let _ = b"\u{a66e}";
//~^ ERROR unicode escape sequences cannot be used as a byte or in a byte string

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only -Z continue-parse-after-error
fn main() {
0b121; //~ ERROR invalid digit for a base 2 literal
0b10_10301; //~ ERROR invalid digit for a base 2 literal

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
// compile-flags: -Z parse-only -Z continue-parse-after-error
static c3: char =
'\x1' //~ ERROR: numeric character escape is too short
;

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
// compile-flags: -Z parse-only -Z continue-parse-after-error
fn main() {
0o1.0; //~ ERROR: octal float literal is not supported

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
// compile-flags: -Z parse-only -Z continue-parse-after-error
// ignore-tidy-cr

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
// compile-flags: -Z parse-only -Z continue-parse-after-error
pub fn main() {
let s = "\u{lol}";

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
// compile-flags: -Z parse-only -Z continue-parse-after-error
trait A {
fn foo(*mut self); //~ ERROR cannot pass self by raw pointer