Move librustc_const_eval to librustc_mir
This commit is contained in:
parent
918b6d7633
commit
e97089dae3
25 changed files with 626 additions and 642 deletions
|
@ -64,7 +64,6 @@ for details on how to format and write long error codes.
|
|||
[librustc](https://github.com/rust-lang/rust/blob/master/src/librustc/diagnostics.rs),
|
||||
[libsyntax](https://github.com/rust-lang/rust/blob/master/src/libsyntax/diagnostics.rs),
|
||||
[librustc_borrowck](https://github.com/rust-lang/rust/blob/master/src/librustc_borrowck/diagnostics.rs),
|
||||
[librustc_const_eval](https://github.com/rust-lang/rust/blob/master/src/librustc_const_eval/diagnostics.rs),
|
||||
[librustc_metadata](https://github.com/rust-lang/rust/blob/master/src/librustc_metadata/diagnostics.rs),
|
||||
[librustc_mir](https://github.com/rust-lang/rust/blob/master/src/librustc_mir/diagnostics.rs),
|
||||
[librustc_passes](https://github.com/rust-lang/rust/blob/master/src/librustc_passes/diagnostics.rs),
|
||||
|
|
|
@ -63,7 +63,6 @@
|
|||
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
|
||||
use hir::map::DefPathHash;
|
||||
use hir::{HirId, ItemLocalId};
|
||||
use mir;
|
||||
|
||||
use ich::Fingerprint;
|
||||
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
|
||||
|
|
|
@ -13,7 +13,6 @@ use hir::def_id::{CrateNum, DefId, DefIndex};
|
|||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::maps::queries;
|
||||
use ty::subst::Substs;
|
||||
use mir;
|
||||
|
||||
use std::hash::Hash;
|
||||
use syntax_pos::symbol::InternedString;
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
name = "rustc_const_eval"
|
||||
version = "0.0.0"
|
||||
|
||||
[lib]
|
||||
name = "rustc_const_eval"
|
||||
path = "lib.rs"
|
||||
crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
arena = { path = "../libarena" }
|
||||
log = "0.4"
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_const_math = { path = "../librustc_const_math" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
|
@ -1,571 +0,0 @@
|
|||
// 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##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
match Some(0) {
|
||||
Some(bar) => {/* ... */}
|
||||
x => {/* ... */} // This handles the `None` case
|
||||
_ => {/* ... */} // 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##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
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
|
||||
fn foo(x: Option<String>) {
|
||||
match x {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0003: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
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,E0004
|
||||
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,E0005
|
||||
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:
|
||||
|
||||
```
|
||||
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,E0007
|
||||
let x = Some("s".to_string());
|
||||
|
||||
match x {
|
||||
op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings
|
||||
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,E0008
|
||||
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 becomes unavailable in the body of the arm.
|
||||
|
||||
The problem above can be solved by using the `ref` keyword.
|
||||
|
||||
```
|
||||
match Some("hi".to_string()) {
|
||||
Some(ref s) if s.len() == 0 => {},
|
||||
_ => {},
|
||||
}
|
||||
```
|
||||
|
||||
Though this example seems innocuous and easy to solve, the problem becomes clear
|
||||
when it encounters functions which consume the value:
|
||||
|
||||
```compile_fail,E0008
|
||||
struct A{}
|
||||
|
||||
impl A {
|
||||
fn consume(self) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = Some(A{});
|
||||
match a {
|
||||
Some(y) if y.consume() > 0 => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this situation, even the `ref` keyword cannot solve it, since borrowed
|
||||
content cannot be moved. This problem cannot be solved generally. If the value
|
||||
can be cloned, here is a not-so-specific solution:
|
||||
|
||||
```
|
||||
#[derive(Clone)]
|
||||
struct A{}
|
||||
|
||||
impl A {
|
||||
fn consume(self) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = Some(A{});
|
||||
match a{
|
||||
Some(ref y) if y.clone().consume() > 0 => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If the value will be consumed in the pattern guard, using its clone will not
|
||||
move its ownership, so the code works.
|
||||
"##,
|
||||
|
||||
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,E0009
|
||||
struct X { x: (), }
|
||||
|
||||
let x = Some((X { x: () }, X { x: () }));
|
||||
match x {
|
||||
Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the
|
||||
// same pattern
|
||||
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,E0162
|
||||
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.
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Try this instead:
|
||||
|
||||
```
|
||||
struct Irrefutable(i32);
|
||||
let irr = Irrefutable(0);
|
||||
|
||||
let Irrefutable(x) = irr;
|
||||
println!("{}", 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,E0165
|
||||
struct Irrefutable(i32);
|
||||
let irr = Irrefutable(0);
|
||||
|
||||
// This fails to compile because the match is irrefutable.
|
||||
while let Irrefutable(x) = irr {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Try this instead:
|
||||
|
||||
```no_run
|
||||
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:
|
||||
|
||||
```
|
||||
use Method::*;
|
||||
enum Method { GET, POST }
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
If you want others to be able to import variants from your module directly, use
|
||||
`pub use`:
|
||||
|
||||
```
|
||||
pub use Method::*;
|
||||
pub enum Method { GET, POST }
|
||||
# fn main() {}
|
||||
```
|
||||
"##,
|
||||
|
||||
|
||||
E0297: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
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,E0005
|
||||
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,E0301
|
||||
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,E0302
|
||||
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.
|
||||
|
||||
Before:
|
||||
|
||||
```compile_fail,E0303
|
||||
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
|
||||
"##,
|
||||
|
||||
}
|
||||
|
||||
|
||||
register_diagnostics! {
|
||||
// E0298, // cannot compare constants
|
||||
// E0299, // mismatched types between arms
|
||||
// E0471, // constant evaluation error (in pattern)
|
||||
}
|
|
@ -17,7 +17,6 @@ rustc = { path = "../librustc" }
|
|||
rustc_allocator = { path = "../librustc_allocator" }
|
||||
rustc_back = { path = "../librustc_back" }
|
||||
rustc_borrowck = { path = "../librustc_borrowck" }
|
||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
rustc_incremental = { path = "../librustc_incremental" }
|
||||
|
|
|
@ -37,7 +37,7 @@ use rustc_privacy;
|
|||
use rustc_plugin::registry::Registry;
|
||||
use rustc_plugin as plugin;
|
||||
use rustc_passes::{self, ast_validation, loops, consts, hir_stats};
|
||||
use rustc_const_eval::{self, check_match};
|
||||
use rustc_mir::const_eval::check_match;
|
||||
use super::Compilation;
|
||||
|
||||
use serialize::json;
|
||||
|
@ -942,7 +942,6 @@ pub fn default_provide(providers: &mut ty::maps::Providers) {
|
|||
ty::provide(providers);
|
||||
traits::provide(providers);
|
||||
reachable::provide(providers);
|
||||
rustc_const_eval::provide(providers);
|
||||
rustc_passes::provide(providers);
|
||||
middle::region::provide(providers);
|
||||
cstore::provide(providers);
|
||||
|
|
|
@ -35,7 +35,6 @@ extern crate rustc;
|
|||
extern crate rustc_allocator;
|
||||
extern crate rustc_back;
|
||||
extern crate rustc_borrowck;
|
||||
extern crate rustc_const_eval;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_errors as errors;
|
||||
extern crate rustc_passes;
|
||||
|
@ -1566,7 +1565,6 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
|
|||
// FIXME: need to figure out a way to get these back in here
|
||||
// all_errors.extend_from_slice(get_trans(sess).diagnostics());
|
||||
all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS);
|
||||
all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
|
||||
all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
|
||||
all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS);
|
||||
all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS);
|
||||
|
|
|
@ -12,6 +12,6 @@ test = false
|
|||
[dependencies]
|
||||
log = "0.4"
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
||||
rustc_mir = { path = "../librustc_mir"}
|
||||
syntax = { path = "../libsyntax" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
|
|
|
@ -39,7 +39,7 @@ extern crate syntax;
|
|||
extern crate rustc;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate rustc_const_eval;
|
||||
extern crate rustc_mir;
|
||||
extern crate syntax_pos;
|
||||
|
||||
use rustc::lint;
|
||||
|
|
|
@ -15,7 +15,7 @@ use rustc::ty::subst::Substs;
|
|||
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
|
||||
use rustc::ty::layout::{self, LayoutOf};
|
||||
use middle::const_val::ConstVal;
|
||||
use rustc_const_eval::ConstContext;
|
||||
use rustc_mir::const_eval::ConstContext;
|
||||
use rustc::mir::interpret::{Value, PrimVal};
|
||||
use util::nodemap::FxHashSet;
|
||||
use lint::{LateContext, LintContext, LintArray};
|
||||
|
|
|
@ -9,13 +9,13 @@ path = "lib.rs"
|
|||
crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
arena = { path = "../libarena" }
|
||||
bitflags = "1.0"
|
||||
graphviz = { path = "../libgraphviz" }
|
||||
log = "0.4"
|
||||
log_settings = "0.1.1"
|
||||
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_errors = { path = "../librustc_errors" }
|
||||
|
|
|
@ -21,7 +21,7 @@ use rustc::ty::{self, Ty, TyCtxt};
|
|||
use rustc::ty::subst::Substs;
|
||||
use rustc::util::nodemap::NodeMap;
|
||||
use rustc_back::PanicStrategy;
|
||||
use rustc_const_eval::pattern::{BindingMode, PatternKind};
|
||||
use const_eval::pattern::{BindingMode, PatternKind};
|
||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
use shim;
|
||||
use std::mem;
|
||||
|
|
|
@ -13,15 +13,15 @@ use self::Usefulness::*;
|
|||
use self::WitnessPreference::*;
|
||||
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use eval::{compare_const_vals};
|
||||
use const_eval::eval::{compare_const_vals};
|
||||
|
||||
use rustc_const_math::ConstInt;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
use pattern::{FieldPattern, Pattern, PatternKind};
|
||||
use pattern::{PatternFoldable, PatternFolder};
|
||||
use const_eval::pattern::{FieldPattern, Pattern, PatternKind};
|
||||
use const_eval::pattern::{PatternFoldable, PatternFolder};
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::RangeEnd;
|
|
@ -8,11 +8,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
|
||||
use _match::Usefulness::*;
|
||||
use _match::WitnessPreference::*;
|
||||
use const_eval::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
|
||||
use const_eval::_match::Usefulness::*;
|
||||
use const_eval::_match::WitnessPreference::*;
|
||||
|
||||
use pattern::{Pattern, PatternContext, PatternError, PatternKind};
|
||||
use const_eval::pattern::{Pattern, PatternContext, PatternError, PatternKind};
|
||||
|
||||
use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
|
||||
use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
|
18
src/librustc_mir/const_eval/mod.rs
Normal file
18
src/librustc_mir/const_eval/mod.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
// 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.
|
||||
|
||||
//! constant evaluation on the HIR and code to validate patterns/matches
|
||||
|
||||
mod eval;
|
||||
mod _match;
|
||||
pub mod check_match;
|
||||
pub mod pattern;
|
||||
|
||||
pub use self::eval::*;
|
|
@ -8,7 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use eval;
|
||||
use const_eval::eval;
|
||||
use interpret::{const_val_field, const_discr};
|
||||
|
||||
use rustc::middle::const_val::{ConstEvalErr, ConstVal, ConstAggregate};
|
||||
use rustc::mir::{Field, BorrowKind, Mutability};
|
||||
|
@ -693,7 +694,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
return match expr.node {
|
||||
hir::ExprLit(ref lit) => {
|
||||
let ty = self.tables.expr_ty(expr);
|
||||
match ::eval::lit_to_const(&lit.node, self.tcx, ty, false) {
|
||||
match super::eval::lit_to_const(&lit.node, self.tcx, ty, false) {
|
||||
Ok(value) => PatternKind::Constant {
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
ty,
|
||||
|
@ -716,7 +717,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
hir::ExprLit(ref lit) => lit,
|
||||
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
|
||||
};
|
||||
match ::eval::lit_to_const(&lit.node, self.tcx, ty, true) {
|
||||
match super::eval::lit_to_const(&lit.node, self.tcx, ty, true) {
|
||||
Ok(value) => PatternKind::Constant {
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
ty,
|
||||
|
@ -782,9 +783,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
|
||||
match cv.val {
|
||||
ConstVal::Value(val) => {
|
||||
let discr = self.tcx.const_discr(self.param_env.and((
|
||||
instance, val, cv.ty
|
||||
))).unwrap();
|
||||
let discr = const_discr(
|
||||
self.tcx, self.param_env, instance, val, cv.ty
|
||||
).unwrap();
|
||||
let variant_index = adt_def
|
||||
.discriminants(self.tcx)
|
||||
.position(|var| var.to_u128_unchecked() == discr)
|
||||
|
@ -801,8 +802,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
.map(|(i, _)| {
|
||||
let field = Field::new(i);
|
||||
let val = match cv.val {
|
||||
ConstVal::Value(miri) => self.tcx.const_val_field(
|
||||
self.param_env.and((instance, field, miri, cv.ty)),
|
||||
ConstVal::Value(miri) => const_val_field(
|
||||
self.tcx, self.param_env, instance, field, miri, cv.ty,
|
||||
).unwrap(),
|
||||
_ => bug!("{:#?} is not a valid tuple", cv),
|
||||
};
|
||||
|
@ -844,8 +845,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
ConstVal::Aggregate(ConstAggregate::Struct(consts)) => {
|
||||
consts.iter().find(|&&(name, _)| name == f.name).unwrap().1
|
||||
},
|
||||
ConstVal::Value(miri) => self.tcx.const_val_field(
|
||||
self.param_env.and((instance, field, miri, cv.ty)),
|
||||
ConstVal::Value(miri) => const_val_field(
|
||||
self.tcx, self.param_env, instance, field, miri, cv.ty,
|
||||
).unwrap(),
|
||||
_ => bug!("{:#?} is not a valid tuple", cv),
|
||||
};
|
||||
|
@ -862,8 +863,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
let field = Field::new(i);
|
||||
let val = match cv.val {
|
||||
ConstVal::Aggregate(ConstAggregate::Tuple(consts)) => consts[i],
|
||||
ConstVal::Value(miri) => self.tcx.const_val_field(
|
||||
self.param_env.and((instance, field, miri, cv.ty)),
|
||||
ConstVal::Value(miri) => const_val_field(
|
||||
self.tcx, self.param_env, instance, field, miri, cv.ty,
|
||||
).unwrap(),
|
||||
_ => bug!("{:#?} is not a valid tuple", cv),
|
||||
};
|
||||
|
@ -882,8 +883,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
let val = match cv.val {
|
||||
ConstVal::Aggregate(ConstAggregate::Array(consts)) => consts[i],
|
||||
ConstVal::Aggregate(ConstAggregate::Repeat(cv, _)) => cv,
|
||||
ConstVal::Value(miri) => self.tcx.const_val_field(
|
||||
self.param_env.and((instance, field, miri, cv.ty)),
|
||||
ConstVal::Value(miri) => const_val_field(
|
||||
self.tcx, self.param_env, instance, field, miri, cv.ty,
|
||||
).unwrap(),
|
||||
_ => bug!("{:#?} is not a valid tuple", cv),
|
||||
};
|
|
@ -12,6 +12,553 @@
|
|||
|
||||
register_long_diagnostics! {
|
||||
|
||||
|
||||
E0001: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
match Some(0) {
|
||||
Some(bar) => {/* ... */}
|
||||
x => {/* ... */} // This handles the `None` case
|
||||
_ => {/* ... */} // 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##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
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
|
||||
fn foo(x: Option<String>) {
|
||||
match x {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0003: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
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,E0004
|
||||
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,E0005
|
||||
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:
|
||||
|
||||
```
|
||||
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,E0007
|
||||
let x = Some("s".to_string());
|
||||
|
||||
match x {
|
||||
op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings
|
||||
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,E0008
|
||||
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 becomes unavailable in the body of the arm.
|
||||
|
||||
The problem above can be solved by using the `ref` keyword.
|
||||
|
||||
```
|
||||
match Some("hi".to_string()) {
|
||||
Some(ref s) if s.len() == 0 => {},
|
||||
_ => {},
|
||||
}
|
||||
```
|
||||
|
||||
Though this example seems innocuous and easy to solve, the problem becomes clear
|
||||
when it encounters functions which consume the value:
|
||||
|
||||
```compile_fail,E0008
|
||||
struct A{}
|
||||
|
||||
impl A {
|
||||
fn consume(self) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = Some(A{});
|
||||
match a {
|
||||
Some(y) if y.consume() > 0 => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this situation, even the `ref` keyword cannot solve it, since borrowed
|
||||
content cannot be moved. This problem cannot be solved generally. If the value
|
||||
can be cloned, here is a not-so-specific solution:
|
||||
|
||||
```
|
||||
#[derive(Clone)]
|
||||
struct A{}
|
||||
|
||||
impl A {
|
||||
fn consume(self) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = Some(A{});
|
||||
match a{
|
||||
Some(ref y) if y.clone().consume() > 0 => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If the value will be consumed in the pattern guard, using its clone will not
|
||||
move its ownership, so the code works.
|
||||
"##,
|
||||
|
||||
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,E0009
|
||||
struct X { x: (), }
|
||||
|
||||
let x = Some((X { x: () }, X { x: () }));
|
||||
match x {
|
||||
Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the
|
||||
// same pattern
|
||||
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,E0162
|
||||
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.
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Try this instead:
|
||||
|
||||
```
|
||||
struct Irrefutable(i32);
|
||||
let irr = Irrefutable(0);
|
||||
|
||||
let Irrefutable(x) = irr;
|
||||
println!("{}", 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,E0165
|
||||
struct Irrefutable(i32);
|
||||
let irr = Irrefutable(0);
|
||||
|
||||
// This fails to compile because the match is irrefutable.
|
||||
while let Irrefutable(x) = irr {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Try this instead:
|
||||
|
||||
```no_run
|
||||
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:
|
||||
|
||||
```
|
||||
use Method::*;
|
||||
enum Method { GET, POST }
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
If you want others to be able to import variants from your module directly, use
|
||||
`pub use`:
|
||||
|
||||
```
|
||||
pub use Method::*;
|
||||
pub enum Method { GET, POST }
|
||||
# fn main() {}
|
||||
```
|
||||
"##,
|
||||
|
||||
|
||||
E0297: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
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,E0005
|
||||
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,E0301
|
||||
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,E0302
|
||||
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.
|
||||
|
||||
Before:
|
||||
|
||||
```compile_fail,E0303
|
||||
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
|
||||
"##,
|
||||
|
||||
E0010: r##"
|
||||
The value of statics and constants must be known at compile time, and they live
|
||||
for the entire lifetime of a program. Creating a boxed value allocates memory on
|
||||
|
@ -1771,6 +2318,9 @@ b.resume();
|
|||
}
|
||||
|
||||
register_diagnostics! {
|
||||
// E0298, // cannot compare constants
|
||||
// E0299, // mismatched types between arms
|
||||
// E0471, // constant evaluation error (in pattern)
|
||||
// E0385, // {} in an aliasable location
|
||||
E0493, // destructors cannot be evaluated at compile-time
|
||||
E0524, // two closures require unique access to `..` at the same time
|
||||
|
|
|
@ -27,7 +27,7 @@ use self::cx::Cx;
|
|||
|
||||
pub mod cx;
|
||||
|
||||
pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
|
||||
pub use const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum LintLevel {
|
||||
|
|
|
@ -5,7 +5,7 @@ use rustc::hir::def_id::DefId;
|
|||
use rustc::mir;
|
||||
use rustc::middle::const_val::ErrKind::{CheckMatchError, TypeckError};
|
||||
use rustc::middle::const_val::{ConstEvalErr, ConstVal};
|
||||
use rustc_const_eval::{lookup_const_by_id, ConstContext};
|
||||
use const_eval::{lookup_const_by_id, ConstContext};
|
||||
use rustc::mir::Field;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
|
@ -306,16 +306,19 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
|
|||
|
||||
pub fn const_val_field<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
field: mir::Field,
|
||||
val: Value,
|
||||
ty: Ty<'tcx>,
|
||||
) -> ::rustc::middle::const_val::EvalResult<'tcx> {
|
||||
trace!("const_val_field: {:#?}", key);
|
||||
match const_val_field_inner(tcx, key) {
|
||||
match const_val_field_inner(tcx, param_env, instance, field, val, ty) {
|
||||
Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Value(field),
|
||||
ty,
|
||||
})),
|
||||
Err(err) => Err(ConstEvalErr {
|
||||
span: tcx.def_span(key.value.0.def_id()),
|
||||
span: tcx.def_span(instance.def_id()),
|
||||
kind: err.into(),
|
||||
}),
|
||||
}
|
||||
|
@ -323,11 +326,14 @@ pub fn const_val_field<'a, 'tcx>(
|
|||
|
||||
fn const_val_field_inner<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
field: mir::Field,
|
||||
value: Value,
|
||||
ty: Ty<'tcx>,
|
||||
) -> ::rustc::mir::interpret::EvalResult<'tcx, (Value, Ty<'tcx>)> {
|
||||
trace!("const_val_field: {:#?}", key);
|
||||
let (instance, field, value, ty) = key.value;
|
||||
let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
|
||||
trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
|
||||
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
|
||||
let (mut field, ty) = match value {
|
||||
Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, field, ty)?.expect("const_val_field on non-field"),
|
||||
Value::ByRef(ptr, align) => {
|
||||
|
@ -348,11 +354,13 @@ fn const_val_field_inner<'a, 'tcx>(
|
|||
|
||||
pub fn const_discr<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, Value, Ty<'tcx>)>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
value: Value,
|
||||
ty: Ty<'tcx>,
|
||||
) -> EvalResult<'tcx, u128> {
|
||||
trace!("const_discr: {:#?}", key);
|
||||
let (instance, value, ty) = key.value;
|
||||
let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
|
||||
trace!("const_discr: {:?}, {:?}, {:?}", instance, value, ty);
|
||||
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
|
||||
let (ptr, align) = match value {
|
||||
Value::ByValPair(..) | Value::ByVal(_) => {
|
||||
let layout = ecx.layout_of(ty)?;
|
||||
|
|
|
@ -16,6 +16,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
|||
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(from_ref)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(catch_expr)]
|
||||
|
@ -38,6 +40,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
|||
#![feature(nonzero)]
|
||||
#![feature(underscore_lifetimes)]
|
||||
|
||||
extern crate arena;
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
#[macro_use] extern crate log;
|
||||
|
@ -52,7 +55,6 @@ extern crate syntax;
|
|||
extern crate syntax_pos;
|
||||
extern crate rustc_back;
|
||||
extern crate rustc_const_math;
|
||||
extern crate rustc_const_eval;
|
||||
extern crate core; // for NonZero
|
||||
extern crate log_settings;
|
||||
extern crate rustc_apfloat;
|
||||
|
@ -69,6 +71,7 @@ pub mod transform;
|
|||
pub mod util;
|
||||
pub mod interpret;
|
||||
pub mod monomorphize;
|
||||
pub mod const_eval;
|
||||
|
||||
use rustc::ty::maps::Providers;
|
||||
|
||||
|
@ -77,6 +80,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
shim::provide(providers);
|
||||
transform::provide(providers);
|
||||
providers.const_eval = interpret::const_eval_provider;
|
||||
providers.check_match = const_eval::check_match::check_match;
|
||||
}
|
||||
|
||||
__build_diagnostic_array! { librustc_mir, DIAGNOSTICS }
|
||||
|
|
|
@ -11,7 +11,7 @@ crate-type = ["dylib"]
|
|||
[dependencies]
|
||||
log = "0.4"
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
||||
rustc_mir = { path = "../librustc_mir"}
|
||||
rustc_const_math = { path = "../librustc_const_math" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
// by borrowck::gather_loans
|
||||
|
||||
use rustc::ty::cast::CastKind;
|
||||
use rustc_const_eval::ConstContext;
|
||||
use rustc_mir::const_eval::ConstContext;
|
||||
use rustc::middle::const_val::ConstEvalErr;
|
||||
use rustc::middle::const_val::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll};
|
||||
use rustc::middle::const_val::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#[macro_use]
|
||||
extern crate rustc;
|
||||
extern crate rustc_const_eval;
|
||||
extern crate rustc_mir;
|
||||
extern crate rustc_const_math;
|
||||
extern crate rustc_data_structures;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue