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),
|
[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),
|
[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_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_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_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),
|
[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::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
|
||||||
use hir::map::DefPathHash;
|
use hir::map::DefPathHash;
|
||||||
use hir::{HirId, ItemLocalId};
|
use hir::{HirId, ItemLocalId};
|
||||||
use mir;
|
|
||||||
|
|
||||||
use ich::Fingerprint;
|
use ich::Fingerprint;
|
||||||
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
|
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::{self, Ty, TyCtxt};
|
||||||
use ty::maps::queries;
|
use ty::maps::queries;
|
||||||
use ty::subst::Substs;
|
use ty::subst::Substs;
|
||||||
use mir;
|
|
||||||
|
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use syntax_pos::symbol::InternedString;
|
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_allocator = { path = "../librustc_allocator" }
|
||||||
rustc_back = { path = "../librustc_back" }
|
rustc_back = { path = "../librustc_back" }
|
||||||
rustc_borrowck = { path = "../librustc_borrowck" }
|
rustc_borrowck = { path = "../librustc_borrowck" }
|
||||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
|
||||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||||
rustc_errors = { path = "../librustc_errors" }
|
rustc_errors = { path = "../librustc_errors" }
|
||||||
rustc_incremental = { path = "../librustc_incremental" }
|
rustc_incremental = { path = "../librustc_incremental" }
|
||||||
|
|
|
@ -37,7 +37,7 @@ use rustc_privacy;
|
||||||
use rustc_plugin::registry::Registry;
|
use rustc_plugin::registry::Registry;
|
||||||
use rustc_plugin as plugin;
|
use rustc_plugin as plugin;
|
||||||
use rustc_passes::{self, ast_validation, loops, consts, hir_stats};
|
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 super::Compilation;
|
||||||
|
|
||||||
use serialize::json;
|
use serialize::json;
|
||||||
|
@ -942,7 +942,6 @@ pub fn default_provide(providers: &mut ty::maps::Providers) {
|
||||||
ty::provide(providers);
|
ty::provide(providers);
|
||||||
traits::provide(providers);
|
traits::provide(providers);
|
||||||
reachable::provide(providers);
|
reachable::provide(providers);
|
||||||
rustc_const_eval::provide(providers);
|
|
||||||
rustc_passes::provide(providers);
|
rustc_passes::provide(providers);
|
||||||
middle::region::provide(providers);
|
middle::region::provide(providers);
|
||||||
cstore::provide(providers);
|
cstore::provide(providers);
|
||||||
|
|
|
@ -35,7 +35,6 @@ extern crate rustc;
|
||||||
extern crate rustc_allocator;
|
extern crate rustc_allocator;
|
||||||
extern crate rustc_back;
|
extern crate rustc_back;
|
||||||
extern crate rustc_borrowck;
|
extern crate rustc_borrowck;
|
||||||
extern crate rustc_const_eval;
|
|
||||||
extern crate rustc_data_structures;
|
extern crate rustc_data_structures;
|
||||||
extern crate rustc_errors as errors;
|
extern crate rustc_errors as errors;
|
||||||
extern crate rustc_passes;
|
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
|
// 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(get_trans(sess).diagnostics());
|
||||||
all_errors.extend_from_slice(&rustc_trans_utils::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_metadata::DIAGNOSTICS);
|
||||||
all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS);
|
all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS);
|
||||||
all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS);
|
all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS);
|
||||||
|
|
|
@ -12,6 +12,6 @@ test = false
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
rustc = { path = "../librustc" }
|
rustc = { path = "../librustc" }
|
||||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
rustc_mir = { path = "../librustc_mir"}
|
||||||
syntax = { path = "../libsyntax" }
|
syntax = { path = "../libsyntax" }
|
||||||
syntax_pos = { path = "../libsyntax_pos" }
|
syntax_pos = { path = "../libsyntax_pos" }
|
||||||
|
|
|
@ -39,7 +39,7 @@ extern crate syntax;
|
||||||
extern crate rustc;
|
extern crate rustc;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate rustc_const_eval;
|
extern crate rustc_mir;
|
||||||
extern crate syntax_pos;
|
extern crate syntax_pos;
|
||||||
|
|
||||||
use rustc::lint;
|
use rustc::lint;
|
||||||
|
|
|
@ -15,7 +15,7 @@ use rustc::ty::subst::Substs;
|
||||||
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
|
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
|
||||||
use rustc::ty::layout::{self, LayoutOf};
|
use rustc::ty::layout::{self, LayoutOf};
|
||||||
use middle::const_val::ConstVal;
|
use middle::const_val::ConstVal;
|
||||||
use rustc_const_eval::ConstContext;
|
use rustc_mir::const_eval::ConstContext;
|
||||||
use rustc::mir::interpret::{Value, PrimVal};
|
use rustc::mir::interpret::{Value, PrimVal};
|
||||||
use util::nodemap::FxHashSet;
|
use util::nodemap::FxHashSet;
|
||||||
use lint::{LateContext, LintContext, LintArray};
|
use lint::{LateContext, LintContext, LintArray};
|
||||||
|
|
|
@ -9,13 +9,13 @@ path = "lib.rs"
|
||||||
crate-type = ["dylib"]
|
crate-type = ["dylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
arena = { path = "../libarena" }
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
graphviz = { path = "../libgraphviz" }
|
graphviz = { path = "../libgraphviz" }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
log_settings = "0.1.1"
|
log_settings = "0.1.1"
|
||||||
rustc = { path = "../librustc" }
|
rustc = { path = "../librustc" }
|
||||||
rustc_back = { path = "../librustc_back" }
|
rustc_back = { path = "../librustc_back" }
|
||||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
|
||||||
rustc_const_math = { path = "../librustc_const_math" }
|
rustc_const_math = { path = "../librustc_const_math" }
|
||||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||||
rustc_errors = { path = "../librustc_errors" }
|
rustc_errors = { path = "../librustc_errors" }
|
||||||
|
|
|
@ -21,7 +21,7 @@ use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
use rustc::util::nodemap::NodeMap;
|
use rustc::util::nodemap::NodeMap;
|
||||||
use rustc_back::PanicStrategy;
|
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 rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||||
use shim;
|
use shim;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
|
@ -13,15 +13,15 @@ use self::Usefulness::*;
|
||||||
use self::WitnessPreference::*;
|
use self::WitnessPreference::*;
|
||||||
|
|
||||||
use rustc::middle::const_val::ConstVal;
|
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_const_math::ConstInt;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
|
|
||||||
use pattern::{FieldPattern, Pattern, PatternKind};
|
use const_eval::pattern::{FieldPattern, Pattern, PatternKind};
|
||||||
use pattern::{PatternFoldable, PatternFolder};
|
use const_eval::pattern::{PatternFoldable, PatternFolder};
|
||||||
|
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::hir::RangeEnd;
|
use rustc::hir::RangeEnd;
|
|
@ -8,11 +8,11 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
|
use const_eval::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
|
||||||
use _match::Usefulness::*;
|
use const_eval::_match::Usefulness::*;
|
||||||
use _match::WitnessPreference::*;
|
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::{ConsumeMode, Delegate, ExprUseVisitor};
|
||||||
use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
|
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
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// 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::middle::const_val::{ConstEvalErr, ConstVal, ConstAggregate};
|
||||||
use rustc::mir::{Field, BorrowKind, Mutability};
|
use rustc::mir::{Field, BorrowKind, Mutability};
|
||||||
|
@ -693,7 +694,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
return match expr.node {
|
return match expr.node {
|
||||||
hir::ExprLit(ref lit) => {
|
hir::ExprLit(ref lit) => {
|
||||||
let ty = self.tables.expr_ty(expr);
|
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 {
|
Ok(value) => PatternKind::Constant {
|
||||||
value: self.tcx.mk_const(ty::Const {
|
value: self.tcx.mk_const(ty::Const {
|
||||||
ty,
|
ty,
|
||||||
|
@ -716,7 +717,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
hir::ExprLit(ref lit) => lit,
|
hir::ExprLit(ref lit) => lit,
|
||||||
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
|
_ => 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 {
|
Ok(value) => PatternKind::Constant {
|
||||||
value: self.tcx.mk_const(ty::Const {
|
value: self.tcx.mk_const(ty::Const {
|
||||||
ty,
|
ty,
|
||||||
|
@ -782,9 +783,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
|
ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
|
||||||
match cv.val {
|
match cv.val {
|
||||||
ConstVal::Value(val) => {
|
ConstVal::Value(val) => {
|
||||||
let discr = self.tcx.const_discr(self.param_env.and((
|
let discr = const_discr(
|
||||||
instance, val, cv.ty
|
self.tcx, self.param_env, instance, val, cv.ty
|
||||||
))).unwrap();
|
).unwrap();
|
||||||
let variant_index = adt_def
|
let variant_index = adt_def
|
||||||
.discriminants(self.tcx)
|
.discriminants(self.tcx)
|
||||||
.position(|var| var.to_u128_unchecked() == discr)
|
.position(|var| var.to_u128_unchecked() == discr)
|
||||||
|
@ -801,8 +802,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
.map(|(i, _)| {
|
.map(|(i, _)| {
|
||||||
let field = Field::new(i);
|
let field = Field::new(i);
|
||||||
let val = match cv.val {
|
let val = match cv.val {
|
||||||
ConstVal::Value(miri) => self.tcx.const_val_field(
|
ConstVal::Value(miri) => const_val_field(
|
||||||
self.param_env.and((instance, field, miri, cv.ty)),
|
self.tcx, self.param_env, instance, field, miri, cv.ty,
|
||||||
).unwrap(),
|
).unwrap(),
|
||||||
_ => bug!("{:#?} is not a valid tuple", cv),
|
_ => bug!("{:#?} is not a valid tuple", cv),
|
||||||
};
|
};
|
||||||
|
@ -844,8 +845,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
ConstVal::Aggregate(ConstAggregate::Struct(consts)) => {
|
ConstVal::Aggregate(ConstAggregate::Struct(consts)) => {
|
||||||
consts.iter().find(|&&(name, _)| name == f.name).unwrap().1
|
consts.iter().find(|&&(name, _)| name == f.name).unwrap().1
|
||||||
},
|
},
|
||||||
ConstVal::Value(miri) => self.tcx.const_val_field(
|
ConstVal::Value(miri) => const_val_field(
|
||||||
self.param_env.and((instance, field, miri, cv.ty)),
|
self.tcx, self.param_env, instance, field, miri, cv.ty,
|
||||||
).unwrap(),
|
).unwrap(),
|
||||||
_ => bug!("{:#?} is not a valid tuple", cv),
|
_ => bug!("{:#?} is not a valid tuple", cv),
|
||||||
};
|
};
|
||||||
|
@ -862,8 +863,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
let field = Field::new(i);
|
let field = Field::new(i);
|
||||||
let val = match cv.val {
|
let val = match cv.val {
|
||||||
ConstVal::Aggregate(ConstAggregate::Tuple(consts)) => consts[i],
|
ConstVal::Aggregate(ConstAggregate::Tuple(consts)) => consts[i],
|
||||||
ConstVal::Value(miri) => self.tcx.const_val_field(
|
ConstVal::Value(miri) => const_val_field(
|
||||||
self.param_env.and((instance, field, miri, cv.ty)),
|
self.tcx, self.param_env, instance, field, miri, cv.ty,
|
||||||
).unwrap(),
|
).unwrap(),
|
||||||
_ => bug!("{:#?} is not a valid tuple", cv),
|
_ => bug!("{:#?} is not a valid tuple", cv),
|
||||||
};
|
};
|
||||||
|
@ -882,8 +883,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
let val = match cv.val {
|
let val = match cv.val {
|
||||||
ConstVal::Aggregate(ConstAggregate::Array(consts)) => consts[i],
|
ConstVal::Aggregate(ConstAggregate::Array(consts)) => consts[i],
|
||||||
ConstVal::Aggregate(ConstAggregate::Repeat(cv, _)) => cv,
|
ConstVal::Aggregate(ConstAggregate::Repeat(cv, _)) => cv,
|
||||||
ConstVal::Value(miri) => self.tcx.const_val_field(
|
ConstVal::Value(miri) => const_val_field(
|
||||||
self.param_env.and((instance, field, miri, cv.ty)),
|
self.tcx, self.param_env, instance, field, miri, cv.ty,
|
||||||
).unwrap(),
|
).unwrap(),
|
||||||
_ => bug!("{:#?} is not a valid tuple", cv),
|
_ => bug!("{:#?} is not a valid tuple", cv),
|
||||||
};
|
};
|
|
@ -12,6 +12,553 @@
|
||||||
|
|
||||||
register_long_diagnostics! {
|
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##"
|
E0010: r##"
|
||||||
The value of statics and constants must be known at compile time, and they live
|
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
|
for the entire lifetime of a program. Creating a boxed value allocates memory on
|
||||||
|
@ -1771,6 +2318,9 @@ b.resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
register_diagnostics! {
|
register_diagnostics! {
|
||||||
|
// E0298, // cannot compare constants
|
||||||
|
// E0299, // mismatched types between arms
|
||||||
|
// E0471, // constant evaluation error (in pattern)
|
||||||
// E0385, // {} in an aliasable location
|
// E0385, // {} in an aliasable location
|
||||||
E0493, // destructors cannot be evaluated at compile-time
|
E0493, // destructors cannot be evaluated at compile-time
|
||||||
E0524, // two closures require unique access to `..` at the same time
|
E0524, // two closures require unique access to `..` at the same time
|
||||||
|
|
|
@ -27,7 +27,7 @@ use self::cx::Cx;
|
||||||
|
|
||||||
pub mod 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)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum LintLevel {
|
pub enum LintLevel {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use rustc::hir::def_id::DefId;
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::middle::const_val::ErrKind::{CheckMatchError, TypeckError};
|
use rustc::middle::const_val::ErrKind::{CheckMatchError, TypeckError};
|
||||||
use rustc::middle::const_val::{ConstEvalErr, ConstVal};
|
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::mir::Field;
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
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>(
|
pub fn const_val_field<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, '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> {
|
) -> ::rustc::middle::const_val::EvalResult<'tcx> {
|
||||||
trace!("const_val_field: {:#?}", key);
|
match const_val_field_inner(tcx, param_env, instance, field, val, ty) {
|
||||||
match const_val_field_inner(tcx, key) {
|
|
||||||
Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
|
Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
|
||||||
val: ConstVal::Value(field),
|
val: ConstVal::Value(field),
|
||||||
ty,
|
ty,
|
||||||
})),
|
})),
|
||||||
Err(err) => Err(ConstEvalErr {
|
Err(err) => Err(ConstEvalErr {
|
||||||
span: tcx.def_span(key.value.0.def_id()),
|
span: tcx.def_span(instance.def_id()),
|
||||||
kind: err.into(),
|
kind: err.into(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -323,11 +326,14 @@ pub fn const_val_field<'a, 'tcx>(
|
||||||
|
|
||||||
fn const_val_field_inner<'a, 'tcx>(
|
fn const_val_field_inner<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, '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>)> {
|
) -> ::rustc::mir::interpret::EvalResult<'tcx, (Value, Ty<'tcx>)> {
|
||||||
trace!("const_val_field: {:#?}", key);
|
trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
|
||||||
let (instance, field, value, ty) = key.value;
|
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
|
||||||
let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
|
|
||||||
let (mut field, ty) = match value {
|
let (mut field, ty) = match value {
|
||||||
Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, field, ty)?.expect("const_val_field on non-field"),
|
Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, field, ty)?.expect("const_val_field on non-field"),
|
||||||
Value::ByRef(ptr, align) => {
|
Value::ByRef(ptr, align) => {
|
||||||
|
@ -348,11 +354,13 @@ fn const_val_field_inner<'a, 'tcx>(
|
||||||
|
|
||||||
pub fn const_discr<'a, 'tcx>(
|
pub fn const_discr<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, '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> {
|
) -> EvalResult<'tcx, u128> {
|
||||||
trace!("const_discr: {:#?}", key);
|
trace!("const_discr: {:?}, {:?}, {:?}", instance, value, ty);
|
||||||
let (instance, value, ty) = key.value;
|
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
|
||||||
let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
|
|
||||||
let (ptr, align) = match value {
|
let (ptr, align) = match value {
|
||||||
Value::ByValPair(..) | Value::ByVal(_) => {
|
Value::ByValPair(..) | Value::ByVal(_) => {
|
||||||
let layout = ecx.layout_of(ty)?;
|
let layout = ecx.layout_of(ty)?;
|
||||||
|
|
|
@ -16,6 +16,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
||||||
|
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
|
|
||||||
|
#![feature(slice_patterns)]
|
||||||
|
#![feature(from_ref)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(catch_expr)]
|
#![feature(catch_expr)]
|
||||||
|
@ -38,6 +40,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
||||||
#![feature(nonzero)]
|
#![feature(nonzero)]
|
||||||
#![feature(underscore_lifetimes)]
|
#![feature(underscore_lifetimes)]
|
||||||
|
|
||||||
|
extern crate arena;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
@ -52,7 +55,6 @@ extern crate syntax;
|
||||||
extern crate syntax_pos;
|
extern crate syntax_pos;
|
||||||
extern crate rustc_back;
|
extern crate rustc_back;
|
||||||
extern crate rustc_const_math;
|
extern crate rustc_const_math;
|
||||||
extern crate rustc_const_eval;
|
|
||||||
extern crate core; // for NonZero
|
extern crate core; // for NonZero
|
||||||
extern crate log_settings;
|
extern crate log_settings;
|
||||||
extern crate rustc_apfloat;
|
extern crate rustc_apfloat;
|
||||||
|
@ -69,6 +71,7 @@ pub mod transform;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
pub mod interpret;
|
pub mod interpret;
|
||||||
pub mod monomorphize;
|
pub mod monomorphize;
|
||||||
|
pub mod const_eval;
|
||||||
|
|
||||||
use rustc::ty::maps::Providers;
|
use rustc::ty::maps::Providers;
|
||||||
|
|
||||||
|
@ -77,6 +80,7 @@ pub fn provide(providers: &mut Providers) {
|
||||||
shim::provide(providers);
|
shim::provide(providers);
|
||||||
transform::provide(providers);
|
transform::provide(providers);
|
||||||
providers.const_eval = interpret::const_eval_provider;
|
providers.const_eval = interpret::const_eval_provider;
|
||||||
|
providers.check_match = const_eval::check_match::check_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
__build_diagnostic_array! { librustc_mir, DIAGNOSTICS }
|
__build_diagnostic_array! { librustc_mir, DIAGNOSTICS }
|
||||||
|
|
|
@ -11,7 +11,7 @@ crate-type = ["dylib"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
rustc = { path = "../librustc" }
|
rustc = { path = "../librustc" }
|
||||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
rustc_mir = { path = "../librustc_mir"}
|
||||||
rustc_const_math = { path = "../librustc_const_math" }
|
rustc_const_math = { path = "../librustc_const_math" }
|
||||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||||
syntax = { path = "../libsyntax" }
|
syntax = { path = "../libsyntax" }
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
// by borrowck::gather_loans
|
// by borrowck::gather_loans
|
||||||
|
|
||||||
use rustc::ty::cast::CastKind;
|
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::ConstEvalErr;
|
||||||
use rustc::middle::const_val::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll};
|
use rustc::middle::const_val::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll};
|
||||||
use rustc::middle::const_val::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
|
use rustc::middle::const_val::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rustc;
|
extern crate rustc;
|
||||||
extern crate rustc_const_eval;
|
extern crate rustc_mir;
|
||||||
extern crate rustc_const_math;
|
extern crate rustc_const_math;
|
||||||
extern crate rustc_data_structures;
|
extern crate rustc_data_structures;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue