diff --git a/mk/crates.mk b/mk/crates.mk index ba959d2778e..8c80335e772 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -58,7 +58,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ rustc_data_structures rustc_front rustc_platform_intrinsics \ rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \ - rustc_const_eval + rustc_const_eval rustc_const_math HOST_CRATES := syntax syntax_ext $(RUSTC_CRATES) rustdoc fmt_macros \ flate arena graphviz rbml log serialize TOOLS := compiletest rustdoc rustc rustbook error_index_generator @@ -92,36 +92,39 @@ DEPS_test := std getopts term native:rust_test_helpers DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode DEPS_syntax_ext := syntax fmt_macros -DEPS_rustc_const_eval := std syntax +DEPS_rustc_const_math := std syntax log serialize +DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize rustc_front \ + rustc_back graphviz DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml rustc_front\ log graphviz rustc_back rustc_data_structures\ - rustc_const_eval + rustc_const_math DEPS_rustc_back := std syntax rustc_front flate log libc DEPS_rustc_borrowck := rustc rustc_front rustc_mir log graphviz syntax DEPS_rustc_data_structures := std log serialize DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \ rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \ rustc_trans rustc_privacy rustc_lint rustc_front rustc_plugin \ - rustc_metadata syntax_ext rustc_passes rustc_save_analysis + rustc_metadata syntax_ext rustc_passes rustc_save_analysis rustc_const_eval DEPS_rustc_front := std syntax log serialize -DEPS_rustc_lint := rustc log syntax +DEPS_rustc_lint := rustc log syntax rustc_const_eval DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags -DEPS_rustc_metadata := rustc rustc_front syntax rbml rustc_const_eval -DEPS_rustc_passes := syntax rustc core rustc_front -DEPS_rustc_mir := rustc rustc_front syntax rustc_const_eval +DEPS_rustc_metadata := rustc rustc_front syntax rbml rustc_const_math +DEPS_rustc_passes := syntax rustc core rustc_front rustc_const_eval +DEPS_rustc_mir := rustc rustc_front syntax rustc_const_math rustc_const_eval DEPS_rustc_resolve := arena rustc rustc_front log syntax DEPS_rustc_platform_intrinsics := std DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir DEPS_rustc_privacy := rustc rustc_front log syntax DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \ log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics \ - rustc_const_eval + rustc_const_math rustc_const_eval DEPS_rustc_save_analysis := rustc log syntax rustc_front -DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics rustc_const_eval +DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics rustc_const_math \ + rustc_const_eval DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \ - test rustc_lint rustc_front + test rustc_lint rustc_front rustc_const_eval TOOL_DEPS_compiletest := test getopts log diff --git a/src/doc/book/associated-types.md b/src/doc/book/associated-types.md index a0676a33996..cb54ac2419e 100644 --- a/src/doc/book/associated-types.md +++ b/src/doc/book/associated-types.md @@ -131,7 +131,7 @@ declarations. ## Trait objects with associated types There’s one more bit of syntax we should talk about: trait objects. If you -try to create a trait object from an associated type, like this: +try to create a trait object from a trait with an associated type, like this: ```rust,ignore # trait Graph { diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index d2dc5f1ed93..cdbe8696a90 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -18,7 +18,7 @@ log = { path = "../liblog" } rbml = { path = "../librbml" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } -rustc_const_eval = { path = "../librustc_const_eval" } +rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_front = { path = "../librustc_front" } serialize = { path = "../libserialize" } diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 9348c05d444..117b1119c0a 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -14,273 +14,6 @@ // Each message should start and end with a new line, and be wrapped to 80 characters. // In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. register_long_diagnostics! { - -E0001: r##" -This error suggests that the expression arm corresponding to the noted pattern -will never be reached as for all possible values of the expression being -matched, one of the preceding patterns will match. - -This means that perhaps some of the preceding patterns are too general, this -one is too specific or the ordering is incorrect. - -For example, the following `match` block has too many arms: - -```compile_fail -match foo { - Some(bar) => {/* ... */} - None => {/* ... */} - _ => {/* ... */} // All possible cases have already been handled -} -``` - -`match` blocks have their patterns matched in order, so, for example, putting -a wildcard arm above a more specific arm will make the latter arm irrelevant. - -Ensure the ordering of the match arm is correct and remove any superfluous -arms. -"##, - -E0002: r##" -This error indicates that an empty match expression is invalid because the type -it is matching on is non-empty (there exist values of this type). In safe code -it is impossible to create an instance of an empty type, so empty match -expressions are almost never desired. This error is typically fixed by adding -one or more cases to the match expression. - -An example of an empty type is `enum Empty { }`. So, the following will work: - -``` -enum Empty {} - -fn foo(x: Empty) { - match x { - // empty - } -} -``` - -However, this won't: - -```compile_fail -enum Empty {} - -fn foo(x: Option) { - match x { - // empty - } -} -``` -"##, - -E0003: r##" -Not-a-Number (NaN) values cannot be compared for equality and hence can never -match the input to a match expression. So, the following will not compile: - -```compile_fail -const NAN: f32 = 0.0 / 0.0; - -let number = 0.1f32; - -match number { - NAN => { /* ... */ }, - _ => {} -} -``` - -To match against NaN values, you should instead use the `is_nan()` method in a -guard, like so: - -``` -let number = 0.1f32; - -match number { - x if x.is_nan() => { /* ... */ } - _ => {} -} -``` -"##, - -E0004: r##" -This error indicates that the compiler cannot guarantee a matching pattern for -one or more possible inputs to a match expression. Guaranteed matches are -required in order to assign values to match expressions, or alternatively, -determine the flow of execution. Erroneous code example: - -```compile_fail -enum Terminator { - HastaLaVistaBaby, - TalkToMyHand, -} - -let x = Terminator::HastaLaVistaBaby; - -match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered - Terminator::TalkToMyHand => {} -} -``` - -If you encounter this error you must alter your patterns so that every possible -value of the input type is matched. For types with a small number of variants -(like enums) you should probably cover all cases explicitly. Alternatively, the -underscore `_` wildcard pattern can be added after all other patterns to match -"anything else". Example: - -``` -enum Terminator { - HastaLaVistaBaby, - TalkToMyHand, -} - -let x = Terminator::HastaLaVistaBaby; - -match x { - Terminator::TalkToMyHand => {} - Terminator::HastaLaVistaBaby => {} -} - -// or: - -match x { - Terminator::TalkToMyHand => {} - _ => {} -} -``` -"##, - -E0005: r##" -Patterns used to bind names must be irrefutable, that is, they must guarantee -that a name will be extracted in all cases. Erroneous code example: - -```compile_fail -let x = Some(1); -let Some(y) = x; -// error: refutable pattern in local binding: `None` not covered -``` - -If you encounter this error you probably need to use a `match` or `if let` to -deal with the possibility of failure. Example: - -```compile_fail -let x = Some(1); - -match x { - Some(y) => { - // do something - }, - None => {} -} - -// or: - -if let Some(y) = x { - // do something -} -``` -"##, - -E0007: r##" -This error indicates that the bindings in a match arm would require a value to -be moved into more than one location, thus violating unique ownership. Code -like the following is invalid as it requires the entire `Option` to be -moved into a variable called `op_string` while simultaneously requiring the -inner `String` to be moved into a variable called `s`. - -```compile_fail -let x = Some("s".to_string()); - -match x { - op_string @ Some(s) => {}, - None => {}, -} -``` - -See also the error E0303. -"##, - -E0008: r##" -Names bound in match arms retain their type in pattern guards. As such, if a -name is bound by move in a pattern, it should also be moved to wherever it is -referenced in the pattern guard code. Doing so however would prevent the name -from being available in the body of the match arm. Consider the following: - -```compile_fail -match Some("hi".to_string()) { - Some(s) if s.len() == 0 => {}, // use s. - _ => {}, -} -``` - -The variable `s` has type `String`, and its use in the guard is as a variable of -type `String`. The guard code effectively executes in a separate scope to the -body of the arm, so the value would be moved into this anonymous scope and -therefore become unavailable in the body of the arm. Although this example seems -innocuous, the problem is most clear when considering functions that take their -argument by value. - -```compile_fail -match Some("hi".to_string()) { - Some(s) if { drop(s); false } => (), - Some(s) => {}, // use s. - _ => {}, -} -``` - -The value would be dropped in the guard then become unavailable not only in the -body of that arm but also in all subsequent arms! The solution is to bind by -reference when using guards or refactor the entire expression, perhaps by -putting the condition inside the body of the arm. -"##, - -E0009: r##" -In a pattern, all values that don't implement the `Copy` trait have to be bound -the same way. The goal here is to avoid binding simultaneously by-move and -by-ref. - -This limitation may be removed in a future version of Rust. - -Erroneous code example: - -```compile_fail -struct X { x: (), } - -let x = Some((X { x: () }, X { x: () })); -match x { - Some((y, ref z)) => {}, - None => panic!() -} -``` - -You have two solutions: - -Solution #1: Bind the pattern's values the same way. - -``` -struct X { x: (), } - -let x = Some((X { x: () }, X { x: () })); -match x { - Some((ref y, ref z)) => {}, - // or Some((y, z)) => {} - None => panic!() -} -``` - -Solution #2: Implement the `Copy` trait for the `X` structure. - -However, please keep in mind that the first solution should be preferred. - -``` -#[derive(Clone, Copy)] -struct X { x: (), } - -let x = Some((X { x: () }, X { x: () })); -match x { - Some((y, ref z)) => {}, - None => panic!() -} -``` -"##, - E0020: r##" This error indicates that an attempt was made to divide by zero (or take the remainder of a zero divisor) in a static or constant expression. Erroneous @@ -762,128 +495,6 @@ attributes: See also https://doc.rust-lang.org/book/no-stdlib.html "##, -E0158: r##" -`const` and `static` mean different things. A `const` is a compile-time -constant, an alias for a literal value. This property means you can match it -directly within a pattern. - -The `static` keyword, on the other hand, guarantees a fixed location in memory. -This does not always mean that the value is constant. For example, a global -mutex can be declared `static` as well. - -If you want to match against a `static`, consider using a guard instead: - -``` -static FORTY_TWO: i32 = 42; - -match Some(42) { - Some(x) if x == FORTY_TWO => {} - _ => {} -} -``` -"##, - -E0162: r##" -An if-let pattern attempts to match the pattern, and enters the body if the -match was successful. If the match is irrefutable (when it cannot fail to -match), use a regular `let`-binding instead. For instance: - -```compile_fail -struct Irrefutable(i32); -let irr = Irrefutable(0); - -// This fails to compile because the match is irrefutable. -if let Irrefutable(x) = irr { - // This body will always be executed. - foo(x); -} -``` - -Try this instead: - -```ignore -struct Irrefutable(i32); -let irr = Irrefutable(0); - -let Irrefutable(x) = irr; -foo(x); -``` -"##, - -E0165: r##" -A while-let pattern attempts to match the pattern, and enters the body if the -match was successful. If the match is irrefutable (when it cannot fail to -match), use a regular `let`-binding inside a `loop` instead. For instance: - -```compile_fail -struct Irrefutable(i32); -let irr = Irrefutable(0); - -// This fails to compile because the match is irrefutable. -while let Irrefutable(x) = irr { - ... -} - -Try this instead: - -``` -struct Irrefutable(i32); -let irr = Irrefutable(0); - -loop { - let Irrefutable(x) = irr; - ... -} -``` -"##, - -E0170: r##" -Enum variants are qualified by default. For example, given this type: - -``` -enum Method { - GET, - POST, -} -``` - -You would match it using: - -``` -enum Method { - GET, - POST, -} - -let m = Method::GET; - -match m { - Method::GET => {}, - Method::POST => {}, -} -``` - -If you don't qualify the names, the code will bind new variables named "GET" and -"POST" instead. This behavior is likely not what you want, so `rustc` warns when -that happens. - -Qualified names are good practice, and most code works well with them. But if -you prefer them unqualified, you can import the variants into scope: - -```ignore -use Method::*; -enum Method { GET, POST } -``` - -If you want others to be able to import variants from your module directly, use -`pub use`: - -```ignore -pub use Method::*; -enum Method { GET, POST } -``` -"##, - E0229: r##" An associated type binding was done outside of the type parameter declaration and `where` clause. Erroneous code example: @@ -1573,135 +1184,6 @@ that the value provided is a positive integer between quotes, like so: ``` "##, -E0297: r##" -Patterns used to bind names must be irrefutable. That is, they must guarantee -that a name will be extracted in all cases. Instead of pattern matching the -loop variable, consider using a `match` or `if let` inside the loop body. For -instance: - -```compile_fail -let xs : Vec> = vec!(Some(1), None); - -// This fails because `None` is not covered. -for Some(x) in xs { - // ... -} -``` - -Match inside the loop instead: - -``` -let xs : Vec> = vec!(Some(1), None); - -for item in xs { - match item { - Some(x) => {}, - None => {}, - } -} -``` - -Or use `if let`: - -``` -let xs : Vec> = vec!(Some(1), None); - -for item in xs { - if let Some(x) = item { - // ... - } -} -``` -"##, - -E0301: r##" -Mutable borrows are not allowed in pattern guards, because matching cannot have -side effects. Side effects could alter the matched object or the environment -on which the match depends in such a way, that the match would not be -exhaustive. For instance, the following would not match any arm if mutable -borrows were allowed: - -```compile_fail -match Some(()) { - None => { }, - option if option.take().is_none() => { - /* impossible, option is `Some` */ - }, - Some(_) => { } // When the previous match failed, the option became `None`. -} -``` -"##, - -E0302: r##" -Assignments are not allowed in pattern guards, because matching cannot have -side effects. Side effects could alter the matched object or the environment -on which the match depends in such a way, that the match would not be -exhaustive. For instance, the following would not match any arm if assignments -were allowed: - -```compile_fail -match Some(()) { - None => { }, - option if { option = None; false } { }, - Some(_) => { } // When the previous match failed, the option became `None`. -} -``` -"##, - -E0303: r##" -In certain cases it is possible for sub-bindings to violate memory safety. -Updates to the borrow checker in a future version of Rust may remove this -restriction, but for now patterns must be rewritten without sub-bindings. - -```ignore -// Before. -match Some("hi".to_string()) { - ref op_string_ref @ Some(s) => {}, - None => {}, -} - -// After. -match Some("hi".to_string()) { - Some(ref s) => { - let op_string_ref = &Some(s); - // ... - }, - None => {}, -} -``` - -The `op_string_ref` binding has type `&Option<&String>` in both cases. - -See also https://github.com/rust-lang/rust/issues/14587 -"##, - -E0306: r##" -In an array literal `[x; N]`, `N` is the number of elements in the array. This -must be an unsigned integer. Erroneous code example: - -```compile_fail -let x = [0i32; true]; // error: expected positive integer for repeat count, - // found boolean -``` - -Working example: - -``` -let x = [0i32; 2]; -``` -"##, - -E0307: r##" -The length of an array is part of its type. For this reason, this length must -be a compile-time constant. Erroneous code example: - -```compile_fail - let len = 10; - let x = [0i32; len]; // error: expected constant integer for repeat count, - // found variable -``` -"##, - E0308: r##" This error occurs when the compiler was unable to infer the concrete type of a variable. It can occur for several cases, the most common of which is a @@ -1991,8 +1473,6 @@ register_diagnostics! { E0280, // requirement is not satisfied E0284, // cannot resolve type // E0285, // overflow evaluation builtin bounds - E0298, // mismatched types between arms - E0299, // mismatched types between arms // E0300, // unexpanded macro // E0304, // expected signed integer constant // E0305, // expected constant @@ -2003,7 +1483,6 @@ register_diagnostics! { E0315, // cannot invoke closure outside of its lifetime E0316, // nested quantification of lifetimes E0453, // overruled by outer forbid - E0471, // constant evaluation error: .. E0473, // dereference of reference outside its lifetime E0474, // captured variable `..` does not outlive the enclosing closure E0475, // index of slice outside its lifetime diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 6b5f889fcfb..03a08231c74 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -55,7 +55,7 @@ extern crate rustc_front; extern crate rustc_data_structures; extern crate serialize; extern crate collections; -extern crate rustc_const_eval; +extern crate rustc_const_math; #[macro_use] extern crate log; #[macro_use] extern crate syntax; #[macro_use] #[no_link] extern crate rustc_bitflags; @@ -91,8 +91,7 @@ pub mod lint; pub mod middle { pub mod astconv_util; pub mod expr_use_visitor; // STAGE0: increase glitch immunity - pub mod check_match; - pub mod const_eval; + pub mod const_val; pub mod const_qualif; pub mod cstore; pub mod dataflow; diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs new file mode 100644 index 00000000000..a939389c460 --- /dev/null +++ b/src/librustc/middle/const_val.rs @@ -0,0 +1,101 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::parse::token::InternedString; +use syntax::ast; +use std::rc::Rc; +use middle::def_id::DefId; +use std::hash; +use std::mem::transmute; +use rustc_const_math::*; +use self::ConstVal::*; + +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +pub enum ConstVal { + Float(f64), + Integral(ConstInt), + Str(InternedString), + ByteStr(Rc>), + Bool(bool), + Struct(ast::NodeId), + Tuple(ast::NodeId), + Function(DefId), + Array(ast::NodeId, u64), + Repeat(ast::NodeId, u64), + Char(char), + /// A value that only occurs in case `eval_const_expr` reported an error. You should never + /// handle this case. Its sole purpose is to allow more errors to be reported instead of + /// causing a fatal error. + Dummy, +} + +impl hash::Hash for ConstVal { + fn hash(&self, state: &mut H) { + match *self { + Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state), + Integral(a) => a.hash(state), + Str(ref a) => a.hash(state), + ByteStr(ref a) => a.hash(state), + Bool(a) => a.hash(state), + Struct(a) => a.hash(state), + Tuple(a) => a.hash(state), + Function(a) => a.hash(state), + Array(a, n) => { a.hash(state); n.hash(state) }, + Repeat(a, n) => { a.hash(state); n.hash(state) }, + Char(c) => c.hash(state), + Dummy => ().hash(state), + } + } +} + +/// Note that equality for `ConstVal` means that the it is the same +/// constant, not that the rust values are equal. In particular, `NaN +/// == NaN` (at least if it's the same NaN; distinct encodings for NaN +/// are considering unequal). +impl PartialEq for ConstVal { + fn eq(&self, other: &ConstVal) -> bool { + match (self, other) { + (&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)}, + (&Integral(a), &Integral(b)) => a == b, + (&Str(ref a), &Str(ref b)) => a == b, + (&ByteStr(ref a), &ByteStr(ref b)) => a == b, + (&Bool(a), &Bool(b)) => a == b, + (&Struct(a), &Struct(b)) => a == b, + (&Tuple(a), &Tuple(b)) => a == b, + (&Function(a), &Function(b)) => a == b, + (&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn), + (&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn), + (&Char(a), &Char(b)) => a == b, + (&Dummy, &Dummy) => true, // FIXME: should this be false? + _ => false, + } + } +} + +impl Eq for ConstVal { } + +impl ConstVal { + pub fn description(&self) -> &'static str { + match *self { + Float(_) => "float", + Integral(i) => i.description(), + Str(_) => "string literal", + ByteStr(_) => "byte string literal", + Bool(_) => "boolean", + Struct(_) => "struct", + Tuple(_) => "tuple", + Function(_) => "function definition", + Array(..) => "array", + Repeat(..) => "repeat", + Char(..) => "char", + Dummy => "dummy value", + } + } +} diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index b9073810783..bc10d0c90ef 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -9,8 +9,8 @@ // except according to those terms. use graphviz::IntoCow; -use middle::const_eval::ConstVal; -use rustc_const_eval::{ConstUsize, ConstInt}; +use middle::const_val::ConstVal; +use rustc_const_math::{ConstUsize, ConstInt}; use middle::def_id::DefId; use ty::subst::Substs; use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty}; @@ -999,7 +999,7 @@ impl<'tcx> Debug for Literal<'tcx> { /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output. fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { - use middle::const_eval::ConstVal::*; + use middle::const_val::ConstVal::*; match *const_val { Float(f) => write!(fmt, "{:?}", f), Integral(n) => write!(fmt, "{}", n), diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 856902bea3c..403c749fe4b 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::const_eval::ConstVal; +use middle::const_val::ConstVal; use middle::def_id::DefId; use ty::subst::Substs; use ty::{ClosureSubsts, FnOutput, Region, Ty}; use mir::repr::*; -use rustc_const_eval::ConstUsize; +use rustc_const_math::ConstUsize; use rustc_data_structures::tuple_slice::TupleSlice; use syntax::codemap::Span; diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 0eef4b5221a..eba3332c8f7 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -136,6 +136,7 @@ pub struct Options { pub no_trans: bool, pub error_format: ErrorOutputType, pub treat_err_as_bug: bool, + pub continue_parse_after_error: bool, pub mir_opt_level: usize, /// if true, build up the dep-graph @@ -257,6 +258,7 @@ pub fn basic_options() -> Options { parse_only: false, no_trans: false, treat_err_as_bug: false, + continue_parse_after_error: false, mir_opt_level: 1, build_dep_graph: false, dump_dep_graph: false, @@ -631,6 +633,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "run all passes except translation; no output"), treat_err_as_bug: bool = (false, parse_bool, "treat all errors that occur as bugs"), + continue_parse_after_error: bool = (false, parse_bool, + "attempt to recover from parse errors (experimental)"), incr_comp: bool = (false, parse_bool, "enable incremental compilation (experimental)"), dump_dep_graph: bool = (false, parse_bool, @@ -1045,6 +1049,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let parse_only = debugging_opts.parse_only; let no_trans = debugging_opts.no_trans; let treat_err_as_bug = debugging_opts.treat_err_as_bug; + let continue_parse_after_error = debugging_opts.continue_parse_after_error; let mir_opt_level = debugging_opts.mir_opt_level.unwrap_or(1); let incremental_compilation = debugging_opts.incr_comp; let dump_dep_graph = debugging_opts.dump_dep_graph; @@ -1224,6 +1229,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { parse_only: parse_only, no_trans: no_trans, treat_err_as_bug: treat_err_as_bug, + continue_parse_after_error: continue_parse_after_error, mir_opt_level: mir_opt_level, build_dep_graph: incremental_compilation || dump_dep_graph, dump_dep_graph: dump_dep_graph, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d080724fac9..5c754fc12d7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -50,7 +50,7 @@ use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::{DUMMY_SP, Span}; use syntax::parse::token::InternedString; -use rustc_const_eval::ConstInt; +use rustc_const_math::ConstInt; use rustc_front::hir; use rustc_front::hir::{ItemImpl, ItemTrait, PatKind}; diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index b870dc47ec7..a3aa3f31cd1 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -11,8 +11,6 @@ //! misc. type-system utilities too small to deserve their own file use back::svh::Svh; -use middle::const_eval::{self, ConstVal, ErrKind}; -use middle::const_eval::EvalHint::UncheckedExprHint; use middle::def_id::DefId; use ty::subst; use infer; @@ -22,7 +20,7 @@ use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; use ty::{Disr, ParameterEnvironment}; use ty::TypeVariants::*; -use rustc_const_eval::{ConstInt, ConstIsize, ConstUsize}; +use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; use std::cmp; use std::hash::{Hash, SipHasher, Hasher}; @@ -269,41 +267,6 @@ impl<'tcx> TyCtxt<'tcx> { (a, b) } - /// Returns the repeat count for a repeating vector expression. - pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize { - let hint = UncheckedExprHint(self.types.usize); - match const_eval::eval_const_expr_partial(self, count_expr, hint, None) { - Ok(ConstVal::Integral(ConstInt::Usize(count))) => { - let val = count.as_u64(self.sess.target.uint_type); - assert_eq!(val as usize as u64, val); - val as usize - }, - Ok(const_val) => { - span_err!(self.sess, count_expr.span, E0306, - "expected positive integer for repeat count, found {}", - const_val.description()); - 0 - } - Err(err) => { - let err_msg = match count_expr.node { - hir::ExprPath(None, hir::Path { - global: false, - ref segments, - .. - }) if segments.len() == 1 => - format!("found variable"), - _ => match err.kind { - ErrKind::MiscCatchAll => format!("but found {}", err.description()), - _ => format!("but {}", err.description()) - } - }; - span_err!(self.sess, count_expr.span, E0307, - "expected constant integer for repeat count, {}", err_msg); - 0 - } - } - } - /// Given a set of predicates that apply to an object type, returns /// the region bounds that the (erased) `Self` type must /// outlive. Precisely *because* the `Self` type is erased, the diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index f885e9a94d5..f38c60cd1fa 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -11,4 +11,9 @@ crate-type = ["dylib"] [dependencies] log = { path = "../liblog" } serialize = { path = "../libserialize" } +rustc = { path = "../librustc" } +rustc_front = { path = "../librustc_front" } +rustc_back = { path = "../librustc_back" } +rustc_const_math = { path = "../librustc_const_math" } syntax = { path = "../libsyntax" } +graphviz = { path = "../libgraphviz" } diff --git a/src/librustc/middle/check_match.rs b/src/librustc_const_eval/check_match.rs similarity index 97% rename from src/librustc/middle/check_match.rs rename to src/librustc_const_eval/check_match.rs index 79e4b7c0901..f00df1f671f 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -12,22 +12,22 @@ pub use self::Constructor::*; use self::Usefulness::*; use self::WitnessPreference::*; -use dep_graph::DepNode; -use middle::const_eval::{compare_const_vals, ConstVal}; -use middle::const_eval::{eval_const_expr, eval_const_expr_partial}; -use middle::const_eval::{const_expr_to_pat, lookup_const_by_id}; -use middle::const_eval::EvalHint::ExprTypeChecked; -use middle::def::*; -use middle::def_id::{DefId}; -use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; -use middle::expr_use_visitor::{LoanCause, MutateMode}; -use middle::expr_use_visitor as euv; -use infer; -use middle::mem_categorization::{cmt}; -use middle::pat_util::*; -use traits::ProjectionMode; -use ty::*; -use ty; +use rustc::dep_graph::DepNode; +use rustc::middle::const_val::ConstVal; +use ::{eval_const_expr, eval_const_expr_partial, compare_const_vals}; +use ::{const_expr_to_pat, lookup_const_by_id}; +use ::EvalHint::ExprTypeChecked; +use rustc::middle::def::*; +use rustc::middle::def_id::{DefId}; +use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; +use rustc::middle::expr_use_visitor::{LoanCause, MutateMode}; +use rustc::middle::expr_use_visitor as euv; +use rustc::infer; +use rustc::middle::mem_categorization::{cmt}; +use rustc::middle::pat_util::*; +use rustc::traits::ProjectionMode; +use rustc::ty::*; +use rustc::ty; use std::cmp::Ordering; use std::fmt; use std::iter::{FromIterator, IntoIterator, repeat}; @@ -44,7 +44,7 @@ use syntax::codemap::{Span, Spanned, DUMMY_SP}; use rustc_front::fold::{Folder, noop_fold_pat}; use rustc_front::print::pprust::pat_to_string; use syntax::ptr::P; -use util::nodemap::FnvHashMap; +use rustc::util::nodemap::FnvHashMap; pub const DUMMY_WILD_PAT: &'static Pat = &Pat { id: DUMMY_NODE_ID, @@ -546,7 +546,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, ty::TyTuple(_) => PatKind::Tup(pats.collect()), ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { - let v = adt.variant_of_ctor(ctor); + let v = ctor.variant_for_adt(adt); match v.kind() { VariantKind::Struct => { let field_pats: hir::HirVec<_> = v.fields.iter() @@ -617,13 +617,13 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, }) } -impl<'tcx, 'container> ty::AdtDefData<'tcx, 'container> { - fn variant_of_ctor(&self, - ctor: &Constructor) - -> &VariantDefData<'tcx, 'container> { - match ctor { - &Variant(vid) => self.variant_with_id(vid), - _ => self.struct_variant() +impl Constructor { + fn variant_for_adt<'tcx, 'container, 'a>(&self, + adt: &'a ty::AdtDefData<'tcx, 'container>) + -> &'a VariantDefData<'tcx, 'container> { + match self { + &Variant(vid) => adt.variant_with_id(vid), + _ => adt.struct_variant() } } } @@ -843,7 +843,7 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us _ => 1 }, ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { - adt.variant_of_ctor(ctor).fields.len() + ctor.variant_for_adt(adt).fields.len() } ty::TyArray(_, n) => n, _ => 0 @@ -924,7 +924,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], PatKind::Struct(_, ref pattern_fields, _) => { let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def(); let adt = cx.tcx.node_id_to_type(pat_id).ty_adt_def().unwrap(); - let variant = adt.variant_of_ctor(constructor); + let variant = constructor.variant_for_adt(adt); let def_variant = adt.variant_of_def(def); if variant.did == def_variant.did { Some(variant.fields.iter().map(|sf| { diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs new file mode 100644 index 00000000000..4f5176f6b0b --- /dev/null +++ b/src/librustc_const_eval/diagnostics.rs @@ -0,0 +1,545 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_snake_case)] + +// Error messages for EXXXX errors. +// Each message should start and end with a new line, and be wrapped to 80 characters. +// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. +register_long_diagnostics! { + +E0001: r##" +This error suggests that the expression arm corresponding to the noted pattern +will never be reached as for all possible values of the expression being +matched, one of the preceding patterns will match. + +This means that perhaps some of the preceding patterns are too general, this +one is too specific or the ordering is incorrect. + +For example, the following `match` block has too many arms: + +```compile_fail +match foo { + Some(bar) => {/* ... */} + None => {/* ... */} + _ => {/* ... */} // All possible cases have already been handled +} +``` + +`match` blocks have their patterns matched in order, so, for example, putting +a wildcard arm above a more specific arm will make the latter arm irrelevant. + +Ensure the ordering of the match arm is correct and remove any superfluous +arms. +"##, + +E0002: r##" +This error indicates that an empty match expression is invalid because the type +it is matching on is non-empty (there exist values of this type). In safe code +it is impossible to create an instance of an empty type, so empty match +expressions are almost never desired. This error is typically fixed by adding +one or more cases to the match expression. + +An example of an empty type is `enum Empty { }`. So, the following will work: + +``` +enum Empty {} + +fn foo(x: Empty) { + match x { + // empty + } +} +``` + +However, this won't: + +```compile_fail +enum Empty {} + +fn foo(x: Option) { + match x { + // empty + } +} +``` +"##, + + +E0003: r##" +Not-a-Number (NaN) values cannot be compared for equality and hence can never +match the input to a match expression. So, the following will not compile: + +```compile_fail +const NAN: f32 = 0.0 / 0.0; + +let number = 0.1f32; + +match number { + NAN => { /* ... */ }, + _ => {} +} +``` + +To match against NaN values, you should instead use the `is_nan()` method in a +guard, like so: + +``` +let number = 0.1f32; + +match number { + x if x.is_nan() => { /* ... */ } + _ => {} +} +``` +"##, + + +E0004: r##" +This error indicates that the compiler cannot guarantee a matching pattern for +one or more possible inputs to a match expression. Guaranteed matches are +required in order to assign values to match expressions, or alternatively, +determine the flow of execution. Erroneous code example: + +```compile_fail +enum Terminator { + HastaLaVistaBaby, + TalkToMyHand, +} + +let x = Terminator::HastaLaVistaBaby; + +match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered + Terminator::TalkToMyHand => {} +} +``` + +If you encounter this error you must alter your patterns so that every possible +value of the input type is matched. For types with a small number of variants +(like enums) you should probably cover all cases explicitly. Alternatively, the +underscore `_` wildcard pattern can be added after all other patterns to match +"anything else". Example: + +``` +enum Terminator { + HastaLaVistaBaby, + TalkToMyHand, +} + +let x = Terminator::HastaLaVistaBaby; + +match x { + Terminator::TalkToMyHand => {} + Terminator::HastaLaVistaBaby => {} +} + +// or: + +match x { + Terminator::TalkToMyHand => {} + _ => {} +} +``` +"##, + +E0005: r##" +Patterns used to bind names must be irrefutable, that is, they must guarantee +that a name will be extracted in all cases. Erroneous code example: + +```compile_fail +let x = Some(1); +let Some(y) = x; +// error: refutable pattern in local binding: `None` not covered +``` + +If you encounter this error you probably need to use a `match` or `if let` to +deal with the possibility of failure. Example: + +```compile_fail +let x = Some(1); + +match x { + Some(y) => { + // do something + }, + None => {} +} + +// or: + +if let Some(y) = x { + // do something +} +``` +"##, + +E0007: r##" +This error indicates that the bindings in a match arm would require a value to +be moved into more than one location, thus violating unique ownership. Code +like the following is invalid as it requires the entire `Option` to be +moved into a variable called `op_string` while simultaneously requiring the +inner `String` to be moved into a variable called `s`. + +```compile_fail +let x = Some("s".to_string()); + +match x { + op_string @ Some(s) => {}, + None => {}, +} +``` + +See also the error E0303. +"##, + +E0008: r##" +Names bound in match arms retain their type in pattern guards. As such, if a +name is bound by move in a pattern, it should also be moved to wherever it is +referenced in the pattern guard code. Doing so however would prevent the name +from being available in the body of the match arm. Consider the following: + +```compile_fail +match Some("hi".to_string()) { + Some(s) if s.len() == 0 => {}, // use s. + _ => {}, +} +``` + +The variable `s` has type `String`, and its use in the guard is as a variable of +type `String`. The guard code effectively executes in a separate scope to the +body of the arm, so the value would be moved into this anonymous scope and +therefore become unavailable in the body of the arm. Although this example seems +innocuous, the problem is most clear when considering functions that take their +argument by value. + +```compile_fail +match Some("hi".to_string()) { + Some(s) if { drop(s); false } => (), + Some(s) => {}, // use s. + _ => {}, +} +``` + +The value would be dropped in the guard then become unavailable not only in the +body of that arm but also in all subsequent arms! The solution is to bind by +reference when using guards or refactor the entire expression, perhaps by +putting the condition inside the body of the arm. +"##, + +E0009: r##" +In a pattern, all values that don't implement the `Copy` trait have to be bound +the same way. The goal here is to avoid binding simultaneously by-move and +by-ref. + +This limitation may be removed in a future version of Rust. + +Erroneous code example: + +```compile_fail +struct X { x: (), } + +let x = Some((X { x: () }, X { x: () })); +match x { + Some((y, ref z)) => {}, + None => panic!() +} +``` + +You have two solutions: + +Solution #1: Bind the pattern's values the same way. + +``` +struct X { x: (), } + +let x = Some((X { x: () }, X { x: () })); +match x { + Some((ref y, ref z)) => {}, + // or Some((y, z)) => {} + None => panic!() +} +``` + +Solution #2: Implement the `Copy` trait for the `X` structure. + +However, please keep in mind that the first solution should be preferred. + +``` +#[derive(Clone, Copy)] +struct X { x: (), } + +let x = Some((X { x: () }, X { x: () })); +match x { + Some((y, ref z)) => {}, + None => panic!() +} +``` +"##, + +E0158: r##" +`const` and `static` mean different things. A `const` is a compile-time +constant, an alias for a literal value. This property means you can match it +directly within a pattern. + +The `static` keyword, on the other hand, guarantees a fixed location in memory. +This does not always mean that the value is constant. For example, a global +mutex can be declared `static` as well. + +If you want to match against a `static`, consider using a guard instead: + +``` +static FORTY_TWO: i32 = 42; + +match Some(42) { + Some(x) if x == FORTY_TWO => {} + _ => {} +} +``` +"##, + +E0162: r##" +An if-let pattern attempts to match the pattern, and enters the body if the +match was successful. If the match is irrefutable (when it cannot fail to +match), use a regular `let`-binding instead. For instance: + +```compile_fail +struct Irrefutable(i32); +let irr = Irrefutable(0); + +// This fails to compile because the match is irrefutable. +if let Irrefutable(x) = irr { + // This body will always be executed. + foo(x); +} +``` + +Try this instead: + +```ignore +struct Irrefutable(i32); +let irr = Irrefutable(0); + +let Irrefutable(x) = irr; +foo(x); +``` +"##, + +E0165: r##" +A while-let pattern attempts to match the pattern, and enters the body if the +match was successful. If the match is irrefutable (when it cannot fail to +match), use a regular `let`-binding inside a `loop` instead. For instance: + +```compile_fail +struct Irrefutable(i32); +let irr = Irrefutable(0); + +// This fails to compile because the match is irrefutable. +while let Irrefutable(x) = irr { + ... +} + +Try this instead: + +``` +struct Irrefutable(i32); +let irr = Irrefutable(0); + +loop { + let Irrefutable(x) = irr; + ... +} +``` +"##, + +E0170: r##" +Enum variants are qualified by default. For example, given this type: + +``` +enum Method { + GET, + POST, +} +``` + +You would match it using: + +``` +enum Method { + GET, + POST, +} + +let m = Method::GET; + +match m { + Method::GET => {}, + Method::POST => {}, +} +``` + +If you don't qualify the names, the code will bind new variables named "GET" and +"POST" instead. This behavior is likely not what you want, so `rustc` warns when +that happens. + +Qualified names are good practice, and most code works well with them. But if +you prefer them unqualified, you can import the variants into scope: + +```ignore +use Method::*; +enum Method { GET, POST } +``` + +If you want others to be able to import variants from your module directly, use +`pub use`: + +```ignore +pub use Method::*; +enum Method { GET, POST } +``` +"##, + + +E0297: r##" +Patterns used to bind names must be irrefutable. That is, they must guarantee +that a name will be extracted in all cases. Instead of pattern matching the +loop variable, consider using a `match` or `if let` inside the loop body. For +instance: + +```compile_fail +let xs : Vec> = vec!(Some(1), None); + +// This fails because `None` is not covered. +for Some(x) in xs { + // ... +} +``` + +Match inside the loop instead: + +``` +let xs : Vec> = vec!(Some(1), None); + +for item in xs { + match item { + Some(x) => {}, + None => {}, + } +} +``` + +Or use `if let`: + +``` +let xs : Vec> = vec!(Some(1), None); + +for item in xs { + if let Some(x) = item { + // ... + } +} +``` +"##, + +E0301: r##" +Mutable borrows are not allowed in pattern guards, because matching cannot have +side effects. Side effects could alter the matched object or the environment +on which the match depends in such a way, that the match would not be +exhaustive. For instance, the following would not match any arm if mutable +borrows were allowed: + +```compile_fail +match Some(()) { + None => { }, + option if option.take().is_none() => { + /* impossible, option is `Some` */ + }, + Some(_) => { } // When the previous match failed, the option became `None`. +} +``` +"##, + +E0302: r##" +Assignments are not allowed in pattern guards, because matching cannot have +side effects. Side effects could alter the matched object or the environment +on which the match depends in such a way, that the match would not be +exhaustive. For instance, the following would not match any arm if assignments +were allowed: + +```compile_fail +match Some(()) { + None => { }, + option if { option = None; false } { }, + Some(_) => { } // When the previous match failed, the option became `None`. +} +``` +"##, + +E0303: r##" +In certain cases it is possible for sub-bindings to violate memory safety. +Updates to the borrow checker in a future version of Rust may remove this +restriction, but for now patterns must be rewritten without sub-bindings. + +```ignore +// Before. +match Some("hi".to_string()) { + ref op_string_ref @ Some(s) => {}, + None => {}, +} + +// After. +match Some("hi".to_string()) { + Some(ref s) => { + let op_string_ref = &Some(s); + // ... + }, + None => {}, +} +``` + +The `op_string_ref` binding has type `&Option<&String>` in both cases. + +See also https://github.com/rust-lang/rust/issues/14587 +"##, + +E0306: r##" +In an array literal `[x; N]`, `N` is the number of elements in the array. This +must be an unsigned integer. Erroneous code example: + +```compile_fail +let x = [0i32; true]; // error: expected positive integer for repeat count, + // found boolean +``` + +Working example: + +``` +let x = [0i32; 2]; +``` +"##, + +E0307: r##" +The length of an array is part of its type. For this reason, this length must +be a compile-time constant. Erroneous code example: + +```compile_fail + let len = 10; + let x = [0i32; len]; // error: expected constant integer for repeat count, + // found variable +``` +"##, + +} + + +register_diagnostics! { +E0298, // mismatched types between arms +E0299, // mismatched types between arms +E0471, // constant evaluation error: .. +} diff --git a/src/librustc/middle/const_eval.rs b/src/librustc_const_eval/eval.rs similarity index 93% rename from src/librustc/middle/const_eval.rs rename to src/librustc_const_eval/eval.rs index fca2904979c..a36d0b3fcff 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -10,23 +10,24 @@ //#![allow(non_camel_case_types)] -use self::ConstVal::*; +use rustc::middle::const_val::ConstVal::*; +use rustc::middle::const_val::ConstVal; use self::ErrKind::*; use self::EvalHint::*; -use front::map as ast_map; -use front::map::blocks::FnLikeNode; -use lint; -use middle::cstore::{self, CrateStore, InlinedItem}; -use {infer, traits}; -use middle::def::Def; -use middle::def_id::DefId; -use middle::pat_util::def_to_path; -use ty::{self, subst, Ty, TyCtxt}; -use ty::util::IntTypeExt; -use traits::ProjectionMode; -use middle::astconv_util::ast_ty_to_prim_ty; -use util::nodemap::NodeMap; +use rustc::front::map as ast_map; +use rustc::front::map::blocks::FnLikeNode; +use rustc::middle::cstore::{self, CrateStore, InlinedItem}; +use rustc::{infer, traits}; +use rustc::middle::def::Def; +use rustc::middle::def_id::DefId; +use rustc::middle::pat_util::def_to_path; +use rustc::ty::{self, Ty, TyCtxt, subst}; +use rustc::ty::util::IntTypeExt; +use rustc::traits::ProjectionMode; +use rustc::middle::astconv_util::ast_ty_to_prim_ty; +use rustc::util::nodemap::NodeMap; +use rustc::lint; use graphviz::IntoCow; use syntax::ast; @@ -34,7 +35,6 @@ use rustc_front::hir::{Expr, PatKind}; use rustc_front::hir; use rustc_front::intravisit::FnKind; use syntax::codemap::Span; -use syntax::parse::token::InternedString; use syntax::ptr::P; use syntax::codemap; use syntax::attr::IntType; @@ -42,11 +42,8 @@ use syntax::attr::IntType; use std::borrow::Cow; use std::cmp::Ordering; use std::collections::hash_map::Entry::Vacant; -use std::hash; -use std::mem::transmute; -use std::rc::Rc; -use rustc_const_eval::*; +use rustc_const_math::*; macro_rules! math { ($e:expr, $op:expr) => { @@ -241,89 +238,6 @@ pub fn lookup_const_fn_by_id<'tcx>(tcx: &TyCtxt<'tcx>, def_id: DefId) } } -#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub enum ConstVal { - Float(f64), - Integral(ConstInt), - Str(InternedString), - ByteStr(Rc>), - Bool(bool), - Struct(ast::NodeId), - Tuple(ast::NodeId), - Function(DefId), - Array(ast::NodeId, u64), - Repeat(ast::NodeId, u64), - Char(char), - /// A value that only occurs in case `eval_const_expr` reported an error. You should never - /// handle this case. Its sole purpose is to allow more errors to be reported instead of - /// causing a fatal error. - Dummy, -} - -impl hash::Hash for ConstVal { - fn hash(&self, state: &mut H) { - match *self { - Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state), - Integral(a) => a.hash(state), - Str(ref a) => a.hash(state), - ByteStr(ref a) => a.hash(state), - Bool(a) => a.hash(state), - Struct(a) => a.hash(state), - Tuple(a) => a.hash(state), - Function(a) => a.hash(state), - Array(a, n) => { a.hash(state); n.hash(state) }, - Repeat(a, n) => { a.hash(state); n.hash(state) }, - Char(c) => c.hash(state), - Dummy => ().hash(state), - } - } -} - -/// Note that equality for `ConstVal` means that the it is the same -/// constant, not that the rust values are equal. In particular, `NaN -/// == NaN` (at least if it's the same NaN; distinct encodings for NaN -/// are considering unequal). -impl PartialEq for ConstVal { - fn eq(&self, other: &ConstVal) -> bool { - match (self, other) { - (&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)}, - (&Integral(a), &Integral(b)) => a == b, - (&Str(ref a), &Str(ref b)) => a == b, - (&ByteStr(ref a), &ByteStr(ref b)) => a == b, - (&Bool(a), &Bool(b)) => a == b, - (&Struct(a), &Struct(b)) => a == b, - (&Tuple(a), &Tuple(b)) => a == b, - (&Function(a), &Function(b)) => a == b, - (&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn), - (&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn), - (&Char(a), &Char(b)) => a == b, - (&Dummy, &Dummy) => true, // FIXME: should this be false? - _ => false, - } - } -} - -impl Eq for ConstVal { } - -impl ConstVal { - pub fn description(&self) -> &'static str { - match *self { - Float(_) => "float", - Integral(i) => i.description(), - Str(_) => "string literal", - ByteStr(_) => "byte string literal", - Bool(_) => "boolean", - Struct(_) => "struct", - Tuple(_) => "tuple", - Function(_) => "function definition", - Array(..) => "array", - Repeat(..) => "repeat", - Char(..) => "char", - Dummy => "dummy value", - } - } -} - pub fn const_expr_to_pat(tcx: &ty::TyCtxt, expr: &Expr, pat_id: ast::NodeId, span: Span) -> Result, DefId> { let pat_ty = tcx.expr_ty(expr); @@ -352,7 +266,6 @@ pub fn const_expr_to_pat(tcx: &ty::TyCtxt, expr: &Expr, pat_id: ast::NodeId, spa } _ => { } } - let pat = match expr.node { hir::ExprTup(ref exprs) => PatKind::Tup(try!(exprs.iter() @@ -1275,3 +1188,39 @@ pub fn compare_lit_exprs<'tcx>(tcx: &TyCtxt<'tcx>, }; compare_const_vals(&a, &b) } + + +/// Returns the repeat count for a repeating vector expression. +pub fn eval_repeat_count(tcx: &TyCtxt, count_expr: &hir::Expr) -> usize { + let hint = UncheckedExprHint(tcx.types.usize); + match eval_const_expr_partial(tcx, count_expr, hint, None) { + Ok(Integral(Usize(count))) => { + let val = count.as_u64(tcx.sess.target.uint_type); + assert_eq!(val as usize as u64, val); + val as usize + }, + Ok(const_val) => { + span_err!(tcx.sess, count_expr.span, E0306, + "expected positive integer for repeat count, found {}", + const_val.description()); + 0 + } + Err(err) => { + let err_msg = match count_expr.node { + hir::ExprPath(None, hir::Path { + global: false, + ref segments, + .. + }) if segments.len() == 1 => + format!("found variable"), + _ => match err.kind { + MiscCatchAll => format!("but found {}", err.description()), + _ => format!("but {}", err.description()) + } + }; + span_err!(tcx.sess, count_expr.span, E0307, + "expected constant integer for repeat count, {}", err_msg); + 0 + } + } +} diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 80b8c75104a..558ae71756b 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Rusty Mathematics +//! constant evaluation on the HIR and code to validate patterns/matches //! //! # Note //! @@ -25,19 +25,29 @@ #![feature(rustc_private)] #![feature(staged_api)] +#![feature(rustc_diagnostic_macros)] +#![feature(slice_patterns)] +#![feature(iter_arith)] #![feature(question_mark)] -#[macro_use] extern crate log; #[macro_use] extern crate syntax; +#[macro_use] extern crate log; +extern crate rustc; +extern crate rustc_front; +extern crate rustc_back; +extern crate rustc_const_math; +extern crate graphviz; extern crate serialize as rustc_serialize; // used by deriving -mod int; -mod us; -mod is; -mod err; +// NB: This module needs to be declared first so diagnostics are +// registered before they are used. +pub mod diagnostics; -pub use int::*; -pub use us::*; -pub use is::*; -pub use err::ConstMathErr; +mod eval; +pub mod check_match; + +pub use eval::*; + +// Build the diagnostics array at the end so that the metadata includes error use sites. +__build_diagnostic_array! { librustc_const_eval, DIAGNOSTICS } diff --git a/src/librustc_const_math/Cargo.toml b/src/librustc_const_math/Cargo.toml new file mode 100644 index 00000000000..10aadabe22e --- /dev/null +++ b/src/librustc_const_math/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_const_math" +version = "0.0.0" + +[lib] +name = "rustc_const_math" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +serialize = { path = "../libserialize" } +syntax = { path = "../libsyntax" } diff --git a/src/librustc_const_eval/err.rs b/src/librustc_const_math/err.rs similarity index 100% rename from src/librustc_const_eval/err.rs rename to src/librustc_const_math/err.rs diff --git a/src/librustc_const_eval/int.rs b/src/librustc_const_math/int.rs similarity index 99% rename from src/librustc_const_eval/int.rs rename to src/librustc_const_math/int.rs index 7576a984bec..658d4d9a6d2 100644 --- a/src/librustc_const_eval/int.rs +++ b/src/librustc_const_math/int.rs @@ -326,7 +326,7 @@ macro_rules! impl_binop { impl ::std::ops::$op for ConstInt { type Output = Result; fn $func(self, rhs: Self) -> Result { - match try!(self.infer(rhs)) { + match self.infer(rhs)? { (I8(a), I8(b)) => a.$checked_func(b).map(I8), (I16(a), I16(b)) => a.$checked_func(b).map(I16), (I32(a), I32(b)) => a.$checked_func(b).map(I32), @@ -353,7 +353,7 @@ macro_rules! derive_binop { impl ::std::ops::$op for ConstInt { type Output = Result; fn $func(self, rhs: Self) -> Result { - match try!(self.infer(rhs)) { + match self.infer(rhs)? { (I8(a), I8(b)) => Ok(I8(a.$func(b))), (I16(a), I16(b)) => Ok(I16(a.$func(b))), (I32(a), I32(b)) => Ok(I32(a.$func(b))), diff --git a/src/librustc_const_eval/is.rs b/src/librustc_const_math/is.rs similarity index 100% rename from src/librustc_const_eval/is.rs rename to src/librustc_const_math/is.rs diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs new file mode 100644 index 00000000000..9f66aac6e38 --- /dev/null +++ b/src/librustc_const_math/lib.rs @@ -0,0 +1,43 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Rusty Mathematics +//! +//! # Note +//! +//! This API is completely unstable and subject to change. + +#![crate_name = "rustc_const_math"] +#![unstable(feature = "rustc_private", issue = "27812")] +#![crate_type = "dylib"] +#![crate_type = "rlib"] +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] + + +#![feature(rustc_private)] +#![feature(staged_api)] +#![feature(question_mark)] + +#[macro_use] extern crate log; +#[macro_use] extern crate syntax; + +extern crate serialize as rustc_serialize; // used by deriving + +mod int; +mod us; +mod is; +mod err; + +pub use int::*; +pub use us::*; +pub use is::*; +pub use err::ConstMathErr; diff --git a/src/librustc_const_eval/us.rs b/src/librustc_const_math/us.rs similarity index 100% rename from src/librustc_const_eval/us.rs rename to src/librustc_const_math/us.rs diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index c8c51793444..803b919058d 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -17,6 +17,7 @@ log = { path = "../liblog" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_borrowck = { path = "../librustc_borrowck" } +rustc_const_eval = { path = "../librustc_const_eval" } rustc_front = { path = "../librustc_front" } rustc_lint = { path = "../librustc_lint" } rustc_llvm = { path = "../librustc_llvm" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 468dc7b12c1..a0752852dc3 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -38,6 +38,7 @@ use rustc_plugin as plugin; use rustc_front::hir; use rustc_front::lowering::{lower_crate, LoweringContext}; use rustc_passes::{no_asm, loops, consts, const_fn, rvalues, static_recursion}; +use rustc_const_eval::check_match; use super::Compilation; use serialize::json; @@ -428,6 +429,8 @@ pub fn phase_1_parse_input<'a>(sess: &'a Session, // memory, but they do not restore the initial state. syntax::ext::mtwt::reset_tables(); token::reset_ident_interner(); + let continue_after_error = sess.opts.continue_parse_after_error; + sess.diagnostic().set_continue_after_error(continue_after_error); let krate = time(sess.time_passes(), "parsing", || { match *input { @@ -443,6 +446,8 @@ pub fn phase_1_parse_input<'a>(sess: &'a Session, } })?; + sess.diagnostic().set_continue_after_error(true); + if sess.opts.debugging_opts.ast_json_noexpand { println!("{}", json::as_json(&krate)); } @@ -851,7 +856,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, time(time_passes, "match checking", - || middle::check_match::check_crate(tcx)); + || check_match::check_crate(tcx)); // this must run before MIR dump, because // "not all control paths return a value" is reported here. diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 057a34c27b1..516c55e1020 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -40,6 +40,7 @@ extern crate libc; extern crate rustc; extern crate rustc_back; extern crate rustc_borrowck; +extern crate rustc_const_eval; extern crate rustc_passes; extern crate rustc_front; extern crate rustc_lint; @@ -1090,6 +1091,7 @@ pub fn diagnostics_registry() -> diagnostics::registry::Registry { all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS); + all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS); Registry::new(&all_errors) } diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 33443957d1b..4821a723279 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -12,5 +12,6 @@ crate-type = ["dylib"] log = { path = "../liblog" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } +rustc_const_eval = { path = "../librustc_const_eval" } rustc_front = { path = "../librustc_front" } syntax = { path = "../libsyntax" } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 9ed21117ceb..6e3a961caca 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -46,6 +46,7 @@ extern crate rustc; extern crate log; extern crate rustc_front; extern crate rustc_back; +extern crate rustc_const_eval; pub use rustc::lint as lint; pub use rustc::middle as middle; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 6322f592573..80733bccf8e 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -14,8 +14,9 @@ use middle::def_id::DefId; use rustc::infer; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; -use middle::const_eval::{eval_const_expr_partial, ConstVal}; -use middle::const_eval::EvalHint::ExprTypeChecked; +use middle::const_val::ConstVal; +use rustc_const_eval::eval_const_expr_partial; +use rustc_const_eval::EvalHint::ExprTypeChecked; use util::nodemap::{FnvHashSet}; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index e8b5a7efdd9..65c2c2d1480 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -15,7 +15,7 @@ rbml = { path = "../librbml" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } -rustc_const_eval = { path = "../librustc_const_eval" } +rustc_const_math = { path = "../librustc_const_math" } rustc_front = { path = "../librustc_front" } rustc_llvm = { path = "../librustc_llvm" } serialize = { path = "../libserialize" } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e6f516ccd33..b9ebd3c3afa 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -36,7 +36,7 @@ use rustc::ty::subst; use rustc::ty::{ImplContainer, TraitContainer}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind}; -use rustc_const_eval::ConstInt; +use rustc_const_math::ConstInt; use rustc::mir; use rustc::mir::visit::MutVisitor; diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index a6c612f5397..674106dd82a 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -37,7 +37,7 @@ extern crate rustc; extern crate rustc_back; extern crate rustc_front; extern crate rustc_llvm; -extern crate rustc_const_eval; +extern crate rustc_const_math; pub use rustc::middle; diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 99237c9fa5f..f136618b1c9 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -14,6 +14,7 @@ log = { path = "../liblog" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } +rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_front = { path = "../librustc_front" } syntax = { path = "../libsyntax" } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 581e8e35ee8..68563197014 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -15,7 +15,7 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use rustc_data_structures::fnv::FnvHashMap; -use rustc::middle::const_eval::ConstVal; +use rustc::middle::const_val::ConstVal; use rustc::ty::{AdtDef, Ty}; use rustc::mir::repr::*; use hair::*; diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 5a1c3739ef5..dc70cf4ffb9 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -19,7 +19,7 @@ use build::Builder; use build::matches::{Candidate, MatchPair, Test, TestKind}; use hair::*; use rustc_data_structures::fnv::FnvHashMap; -use rustc::middle::const_eval::ConstVal; +use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; use rustc::mir::repr::*; use syntax::codemap::Span; diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index bac7b310dc7..e3093eab22b 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -94,8 +94,8 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::mir::repr::*; use syntax::codemap::{Span, DUMMY_SP}; use syntax::parse::token::intern_and_get_ident; -use rustc::middle::const_eval::ConstVal; -use rustc_const_eval::ConstInt; +use rustc::middle::const_val::ConstVal; +use rustc_const_math::ConstInt; pub struct Scope<'tcx> { /// the scope-id within the scope_datas diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index aa55ee3e3f7..451cdea35a7 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -10,13 +10,14 @@ use hair::*; use rustc_data_structures::fnv::FnvHashMap; -use rustc_const_eval::ConstInt; +use rustc_const_math::ConstInt; use hair::cx::Cx; use hair::cx::block; use hair::cx::to_ref::ToRef; use rustc::front::map; use rustc::middle::def::Def; -use rustc::middle::const_eval::{self, ConstVal}; +use rustc::middle::const_val::ConstVal; +use rustc_const_eval as const_eval; use rustc::middle::region::CodeExtent; use rustc::middle::pat_util; use rustc::ty::{self, VariantDef, Ty}; diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 30467a981d9..e4a8363051b 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -18,7 +18,8 @@ use hair::*; use rustc::mir::repr::*; -use rustc::middle::const_eval::{self, ConstVal}; +use rustc::middle::const_val::ConstVal; +use rustc_const_eval as const_eval; use rustc::middle::def_id::DefId; use rustc::infer::InferCtxt; use rustc::ty::subst::{Subst, Substs}; @@ -26,7 +27,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use syntax::codemap::Span; use syntax::parse::token; use rustc_front::hir; -use rustc_const_eval::{ConstInt, ConstUsize}; +use rustc_const_math::{ConstInt, ConstUsize}; #[derive(Copy, Clone)] pub struct Cx<'a, 'tcx: 'a> { diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 0cb849555f2..c6132a71eef 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -11,7 +11,7 @@ use hair::*; use hair::cx::Cx; use rustc_data_structures::fnv::FnvHashMap; -use rustc::middle::const_eval; +use rustc_const_eval as const_eval; use rustc::middle::def::Def; use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding}; use rustc::ty::{self, Ty}; diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 79c8356bb55..affc1872987 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -16,7 +16,7 @@ use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, TypedConstVal}; -use rustc::middle::const_eval::ConstVal; +use rustc::middle::const_val::ConstVal; use rustc::middle::def_id::DefId; use rustc::middle::region::CodeExtent; use rustc::ty::subst::Substs; diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 67bac196f48..e024fa94fb7 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -32,6 +32,7 @@ extern crate rustc_data_structures; extern crate rustc_front; extern crate rustc_back; extern crate syntax; +extern crate rustc_const_math; extern crate rustc_const_eval; pub mod build; diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index cbde292cb99..00b8f5c0930 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::middle::const_eval::ConstVal; +use rustc::middle::const_val::ConstVal; use rustc::ty::TyCtxt; use rustc::mir::repr::*; use rustc::mir::transform::{MirPass, Pass}; diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index 7cc6510fa1f..02303aa7130 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -11,5 +11,6 @@ crate-type = ["dylib"] [dependencies] log = { path = "../liblog" } rustc = { path = "../librustc" } +rustc_const_eval = { path = "../librustc_const_eval" } rustc_front = { path = "../librustc_front" } syntax = { path = "../libsyntax" } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 571d5bd9bc5..a33b8caee2e 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -26,9 +26,10 @@ use rustc::dep_graph::DepNode; use rustc::ty::cast::{CastKind}; -use rustc::middle::const_eval::{self, ConstEvalErr}; -use rustc::middle::const_eval::ErrKind::IndexOpFeatureGated; -use rustc::middle::const_eval::EvalHint::ExprTypeChecked; +use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs}; +use rustc_const_eval::{eval_const_expr_partial, lookup_const_by_id}; +use rustc_const_eval::ErrKind::IndexOpFeatureGated; +use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc::middle::def::Def; use rustc::middle::def_id::DefId; use rustc::middle::expr_use_visitor as euv; @@ -169,7 +170,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { def_id: DefId, ret_ty: Ty<'tcx>) -> bool { - if let Some(fn_like) = const_eval::lookup_const_fn_by_id(self.tcx, def_id) { + if let Some(fn_like) = lookup_const_fn_by_id(self.tcx, def_id) { if // we are in a static/const initializer self.mode != Mode::Var && @@ -335,7 +336,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { self.global_expr(Mode::Const, &start); self.global_expr(Mode::Const, &end); - match const_eval::compare_lit_exprs(self.tcx, start, end) { + match compare_lit_exprs(self.tcx, start, end) { Some(Ordering::Less) | Some(Ordering::Equal) => {} Some(Ordering::Greater) => { @@ -431,7 +432,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { match node_ty.sty { ty::TyUint(_) | ty::TyInt(_) if div_or_rem => { if !self.qualif.intersects(ConstQualif::NOT_CONST) { - match const_eval::eval_const_expr_partial( + match eval_const_expr_partial( self.tcx, ex, ExprTypeChecked, None) { Ok(_) => {} Err(ConstEvalErr { kind: IndexOpFeatureGated, ..}) => {}, @@ -611,7 +612,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, Some(Def::Const(did)) | Some(Def::AssociatedConst(did)) => { let substs = Some(v.tcx.node_id_item_substs(e.id).substs); - if let Some((expr, _)) = const_eval::lookup_const_by_id(v.tcx, did, substs) { + if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) { let inner = v.global_expr(Mode::Const, expr); v.add_qualif(inner); } diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 91bfb19aa9d..6d217040316 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -30,6 +30,7 @@ extern crate core; extern crate rustc; extern crate rustc_front; +extern crate rustc_const_eval; #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index b7faafeba9a..b798afe25ed 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -17,6 +17,7 @@ log = { path = "../liblog" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } +rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_front = { path = "../librustc_front" } rustc_llvm = { path = "../librustc_llvm" } diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index 008323ee5bf..f545ba2cbe0 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -189,9 +189,8 @@ use self::Opt::*; use self::FailureHandler::*; use llvm::{ValueRef, BasicBlockRef}; -use middle::check_match::StaticInliner; -use middle::check_match; -use middle::const_eval; +use rustc_const_eval::check_match::{self, StaticInliner}; +use rustc_const_eval::{compare_lit_exprs, eval_const_expr}; use middle::def::{Def, DefMap}; use middle::def_id::DefId; use middle::expr_use_visitor as euv; @@ -241,7 +240,7 @@ struct ConstantExpr<'a>(&'a hir::Expr); impl<'a> ConstantExpr<'a> { fn eq(self, other: ConstantExpr<'a>, tcx: &TyCtxt) -> bool { - match const_eval::compare_lit_exprs(tcx, self.0, other.0) { + match compare_lit_exprs(tcx, self.0, other.0) { Some(result) => result == Ordering::Equal, None => panic!("compare_list_exprs: type mismatch"), } @@ -611,11 +610,11 @@ fn enter_opt<'a, 'p, 'blk, 'tcx>( let ctor = match opt { &ConstantValue(ConstantExpr(expr), _) => check_match::ConstantValue( - const_eval::eval_const_expr(bcx.tcx(), &expr) + eval_const_expr(bcx.tcx(), &expr) ), &ConstantRange(ConstantExpr(lo), ConstantExpr(hi), _) => check_match::ConstantRange( - const_eval::eval_const_expr(bcx.tcx(), &lo), - const_eval::eval_const_expr(bcx.tcx(), &hi) + eval_const_expr(bcx.tcx(), &lo), + eval_const_expr(bcx.tcx(), &hi) ), &SliceLengthEqual(n, _) => check_match::Slice(n), diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 8302fc0158c..555c12807ba 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -13,7 +13,8 @@ use llvm; use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr}; use llvm::{InternalLinkage, ValueRef, Bool, True}; use middle::const_qualif::ConstQualif; -use middle::const_eval::{self, ConstEvalErr}; +use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind}; +use rustc_const_eval::eval_repeat_count; use middle::def::Def; use middle::def_id::DefId; use rustc::front::map as hir_map; @@ -38,7 +39,7 @@ use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::cast::{CastTy,IntTy}; use util::nodemap::NodeMap; -use rustc_const_eval::{ConstInt, ConstMathErr, ConstUsize, ConstIsize}; +use rustc_const_math::{ConstInt, ConstMathErr, ConstUsize, ConstIsize}; use rustc_front::hir; @@ -197,7 +198,7 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg_vals: &[ValueRef], param_substs: &'tcx Substs<'tcx>, trueconst: TrueConst) -> Result { - let fn_like = const_eval::lookup_const_fn_by_id(ccx.tcx(), def_id); + let fn_like = lookup_const_fn_by_id(ccx.tcx(), def_id); let fn_like = fn_like.expect("lookup_const_fn_by_id failed in const_fn_call"); let body = match fn_like.body().expr { @@ -228,7 +229,7 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let substs = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &substs.erase_regions()); - match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(substs)) { + match lookup_const_by_id(ccx.tcx(), def_id, Some(substs)) { Some((ref expr, _ty)) => expr, None => { ccx.sess().span_bug(ref_expr.span, "constant item not found") @@ -534,12 +535,12 @@ fn const_err(cx: &CrateContext, Ok(()) }, (Err(err), TrueConst::Yes) => { - let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) }; + let err = ConstEvalErr{ span: e.span, kind: ErrKind::Math(err) }; cx.tcx().sess.span_err(e.span, &err.description()); Err(Compiletime(err)) }, (Err(err), TrueConst::No) => { - let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) }; + let err = ConstEvalErr{ span: e.span, kind: ErrKind::Math(err) }; cx.tcx().sess.span_warn(e.span, &err.description()); Err(Runtime(err)) }, @@ -883,7 +884,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, hir::ExprRepeat(ref elem, ref count) => { let unit_ty = ety.sequence_element_type(cx.tcx()); let llunitty = type_of::type_of(cx, unit_ty); - let n = cx.tcx().eval_repeat_count(count); + let n = eval_repeat_count(cx.tcx(), count); let unit_val = const_expr(cx, &elem, param_substs, fn_args, trueconst)?.0; let vs = vec![unit_val; n]; if val_ty(unit_val) != llunitty { diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 103de7e42af..e9687935538 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -51,6 +51,7 @@ pub extern crate rustc_llvm as llvm; extern crate rustc_mir; extern crate rustc_platform_intrinsics as intrinsics; extern crate serialize; +extern crate rustc_const_math; extern crate rustc_const_eval; #[macro_use] extern crate log; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index be1c3f3b56b..2e154c40875 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -10,8 +10,9 @@ use llvm::ValueRef; use rustc::ty::{Ty, TypeFoldable}; -use rustc::middle::const_eval::{self, ConstVal}; -use rustc_const_eval::ConstInt::*; +use rustc::middle::const_val::ConstVal; +use rustc_const_math::ConstInt::*; +use rustc_const_eval::lookup_const_by_id; use rustc::mir::repr as mir; use abi; use common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral, @@ -114,7 +115,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } let substs = Some(bcx.monomorphize(substs)); - let expr = const_eval::lookup_const_by_id(bcx.tcx(), def_id, substs) + let expr = lookup_const_by_id(bcx.tcx(), def_id, substs) .expect("def was const, but lookup_const_by_id failed").0; // FIXME: this is falling back to translating from HIR. This is not easy to fix, // because we would have somehow adapt const_eval to work on MIR rather than HIR. diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 47fa618ebad..1396883120b 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -11,8 +11,8 @@ use llvm::ValueRef; use rustc::ty::{self, Ty}; use rustc::ty::cast::{CastTy, IntTy}; -use middle::const_eval::ConstVal; -use rustc_const_eval::ConstInt; +use middle::const_val::ConstVal; +use rustc_const_math::ConstInt; use rustc::mir::repr as mir; use asm; diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs index c42bad0bc0b..56ba1b02426 100644 --- a/src/librustc_trans/tvec.rs +++ b/src/librustc_trans/tvec.rs @@ -30,6 +30,7 @@ use value::Value; use rustc::ty::{self, Ty}; use rustc_front::hir; +use rustc_const_eval::eval_repeat_count; use syntax::ast; use syntax::parse::token::InternedString; @@ -218,7 +219,7 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return expr::trans_into(bcx, &element, Ignore); } SaveIn(lldest) => { - match bcx.tcx().eval_repeat_count(&count_expr) { + match eval_repeat_count(bcx.tcx(), &count_expr) { 0 => expr::trans_into(bcx, &element, Ignore), 1 => expr::trans_into(bcx, &element, SaveIn(lldest)), count => { @@ -270,7 +271,7 @@ fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize { }, hir::ExprVec(ref es) => es.len(), hir::ExprRepeat(_, ref count_expr) => { - bcx.tcx().eval_repeat_count(&count_expr) + eval_repeat_count(bcx.tcx(), &count_expr) } _ => bcx.tcx().sess.span_bug(content_expr.span, "unexpected vec content") diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 1c907972863..6f46686feb5 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -16,5 +16,6 @@ fmt_macros = { path = "../libfmt_macros" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } +rustc_const_math = { path = "../librustc_const_math" } rustc_front = { path = "../librustc_front" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index af40b845767..b7d00716f02 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -49,8 +49,9 @@ //! an rptr (`&r.T`) use the region `r` that appears in the rptr. use middle::astconv_util::{prim_ty_to_ty, prohibit_type_params, prohibit_projection}; -use middle::const_eval::{self, ConstVal}; -use middle::const_eval::EvalHint::UncheckedExprHint; +use middle::const_val::ConstVal; +use rustc_const_eval::eval_const_expr_partial; +use rustc_const_eval::EvalHint::UncheckedExprHint; use middle::def::{self, Def}; use middle::def_id::DefId; use middle::resolve_lifetime as rl; @@ -65,7 +66,7 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::FnvHashSet; -use rustc_const_eval::ConstInt; +use rustc_const_math::ConstInt; use syntax::{abi, ast}; use syntax::codemap::{Span, Pos}; @@ -1681,7 +1682,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, } hir::TyFixedLengthVec(ref ty, ref e) => { let hint = UncheckedExprHint(tcx.types.usize); - match const_eval::eval_const_expr_partial(tcx, &e, hint, None) { + match eval_const_expr_partial(tcx, &e, hint, None) { Ok(ConstVal::Integral(ConstInt::Usize(i))) => { let i = i.as_u64(tcx.sess.target.uint_type); assert_eq!(i as usize as u64, i); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 107497a2aa3..d90ba03abd4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -130,6 +130,7 @@ use rustc_front::hir; use rustc_front::hir::{Visibility, PatKind}; use rustc_front::print::pprust; use rustc_back::slice; +use rustc_const_eval::eval_repeat_count; mod assoc; pub mod dropck; @@ -3592,7 +3593,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } hir::ExprRepeat(ref element, ref count_expr) => { check_expr_has_type(fcx, &count_expr, tcx.types.usize); - let count = fcx.tcx().eval_repeat_count(&count_expr); + let count = eval_repeat_count(fcx.tcx(), &count_expr); let uty = match expected { ExpectHasType(uty) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 0b447b2009b..a9ef0fce880 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -66,8 +66,9 @@ use constrained_type_params as ctp; use coherence; use middle::lang_items::SizedTraitLangItem; use middle::resolve_lifetime; -use middle::const_eval::{self, ConstVal}; -use middle::const_eval::EvalHint::UncheckedExprHint; +use middle::const_val::ConstVal; +use rustc_const_eval::EvalHint::UncheckedExprHint; +use rustc_const_eval::eval_const_expr_partial; use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; @@ -81,7 +82,7 @@ use util::common::{ErrorReported, MemoizationMap}; use util::nodemap::{FnvHashMap, FnvHashSet}; use write_ty_to_tcx; -use rustc_const_eval::ConstInt; +use rustc_const_math::ConstInt; use std::cell::RefCell; use std::collections::HashSet; @@ -1045,7 +1046,7 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>, let ty_hint = repr_ty.to_ty(tcx); let hint = UncheckedExprHint(ty_hint); - match const_eval::eval_const_expr_partial(tcx, e, hint, None) { + match eval_const_expr_partial(tcx, e, hint, None) { Ok(ConstVal::Integral(i)) => { // FIXME: eval_const_expr_partial should return an error if the hint is wrong match (repr_ty, i) { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 9b0fdd8a2e3..c3ba9182343 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -92,6 +92,7 @@ extern crate rustc; extern crate rustc_platform_intrinsics as intrinsics; extern crate rustc_front; extern crate rustc_back; +extern crate rustc_const_math; extern crate rustc_const_eval; pub use rustc::dep_graph; diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 6b0ad30f450..3950131129c 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -14,6 +14,7 @@ arena = { path = "../libarena" } getopts = { path = "../libgetopts" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } +rustc_const_eval = { path = "../librustc_const_eval" } rustc_driver = { path = "../librustc_driver" } rustc_front = { path = "../librustc_front" } rustc_lint = { path = "../librustc_lint" } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 702c6dd8211..3e4ba47ce4c 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -22,7 +22,8 @@ use rustc::middle::def_id::DefId; use rustc::ty::{self, TyCtxt}; use rustc::ty::subst; use rustc::middle::stability; -use rustc::middle::const_eval; + +use rustc_const_eval::lookup_const_by_id; use core::DocContext; use doctree; @@ -336,7 +337,7 @@ pub fn build_impl(cx: &DocContext, let did = assoc_const.def_id; let type_scheme = tcx.lookup_item_type(did); let default = if assoc_const.has_value { - Some(const_eval::lookup_const_by_id(tcx, did, None) + Some(lookup_const_by_id(tcx, did, None) .unwrap().0.span.to_src(cx)) } else { None @@ -483,10 +484,9 @@ fn build_module(cx: &DocContext, tcx: &TyCtxt, fn build_const(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::Constant { - use rustc::middle::const_eval; use rustc_front::print::pprust; - let (expr, ty) = const_eval::lookup_const_by_id(tcx, did, None).unwrap_or_else(|| { + let (expr, ty) = lookup_const_by_id(tcx, did, None).unwrap_or_else(|| { panic!("expected lookup_const_by_id to succeed for {:?}", did); }); debug!("converting constant expr {:?} to snippet", expr); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 90cb78f46a6..a35fe20b6b6 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -35,6 +35,7 @@ extern crate arena; extern crate getopts; extern crate libc; extern crate rustc; +extern crate rustc_const_eval; extern crate rustc_trans; extern crate rustc_driver; extern crate rustc_resolve; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 7ab5c90b0ab..1d21d2d18e4 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -837,8 +837,6 @@ impl HashMap #[stable(feature = "rust1", since = "1.0.0")] pub fn keys<'a>(&'a self) -> Keys<'a, K, V> { fn first((a, _): (A, B)) -> A { a } - let first: fn((&'a K,&'a V)) -> &'a K = first; // coerce to fn ptr - Keys { inner: self.iter().map(first) } } @@ -862,8 +860,6 @@ impl HashMap #[stable(feature = "rust1", since = "1.0.0")] pub fn values<'a>(&'a self) -> Values<'a, K, V> { fn second((_, b): (A, B)) -> B { b } - let second: fn((&'a K,&'a V)) -> &'a V = second; // coerce to fn ptr - Values { inner: self.iter().map(second) } } @@ -997,8 +993,6 @@ impl HashMap #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self) -> Drain { fn last_two((_, b, c): (A, B, C)) -> (B, C) { (b, c) } - let last_two: fn((SafeHash, K, V)) -> (K, V) = last_two; // coerce to fn pointer - Drain { inner: self.table.drain().map(last_two), } @@ -1404,8 +1398,6 @@ impl IntoIterator for HashMap /// ``` fn into_iter(self) -> IntoIter { fn last_two((_, b, c): (A, B, C)) -> (B, C) { (b, c) } - let last_two: fn((SafeHash, K, V)) -> (K, V) = last_two; - IntoIter { inner: self.table.into_iter().map(last_two) } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index fdde1773a45..24dfcb1a9b7 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -415,8 +415,6 @@ impl HashSet #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self) -> Drain { fn first((a, _): (A, B)) -> A { a } - let first: fn((T, ())) -> T = first; // coerce to fn pointer - Drain { iter: self.map.drain().map(first) } } @@ -892,8 +890,6 @@ impl IntoIterator for HashSet /// ``` fn into_iter(self) -> IntoIter { fn first((a, _): (A, B)) -> A { a } - let first: fn((T, ())) -> T = first; - IntoIter { iter: self.map.into_iter().map(first) } } } diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index 9e1cb60f54f..c8c12d5a883 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -370,6 +370,7 @@ pub struct Handler { emit: RefCell>, pub can_emit_warnings: bool, treat_err_as_bug: bool, + continue_after_error: Cell, delayed_span_bug: RefCell>, } @@ -392,10 +393,15 @@ impl Handler { emit: RefCell::new(e), can_emit_warnings: can_emit_warnings, treat_err_as_bug: treat_err_as_bug, + continue_after_error: Cell::new(true), delayed_span_bug: RefCell::new(None), } } + pub fn set_continue_after_error(&self, continue_after_error: bool) { + self.continue_after_error.set(continue_after_error); + } + pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> { DiagnosticBuilder::new(&self.emit, Level::Cancelled, "") } @@ -612,6 +618,7 @@ impl Handler { lvl: Level) { if lvl == Warning && !self.can_emit_warnings { return } self.emit.borrow_mut().emit(msp, msg, None, lvl); + if !self.continue_after_error.get() { self.abort_if_errors(); } } pub fn emit_with_code(&self, msp: Option<&MultiSpan>, @@ -620,10 +627,12 @@ impl Handler { lvl: Level) { if lvl == Warning && !self.can_emit_warnings { return } self.emit.borrow_mut().emit(msp, msg, Some(code), lvl); + if !self.continue_after_error.get() { self.abort_if_errors(); } } pub fn custom_emit(&self, rsp: RenderSpan, msg: &str, lvl: Level) { if lvl == Warning && !self.can_emit_warnings { return } self.emit.borrow_mut().custom_emit(&rsp, msg, lvl); + if !self.continue_after_error.get() { self.abort_if_errors(); } } } diff --git a/src/test/auxiliary/dummy_mir_pass.rs b/src/test/auxiliary/dummy_mir_pass.rs index 3e1b46522a9..fc1ef4d41a8 100644 --- a/src/test/auxiliary/dummy_mir_pass.rs +++ b/src/test/auxiliary/dummy_mir_pass.rs @@ -16,15 +16,15 @@ #[macro_use] extern crate rustc; extern crate rustc_front; extern crate rustc_plugin; -extern crate rustc_const_eval; +extern crate rustc_const_math; extern crate syntax; use rustc::mir::transform::{self, MirPass}; use rustc::mir::repr::{Mir, Literal}; use rustc::mir::visit::MutVisitor; use rustc::ty; -use rustc::middle::const_eval::ConstVal; -use rustc_const_eval::ConstInt; +use rustc::middle::const_val::ConstVal; +use rustc_const_math::ConstInt; use rustc_plugin::Registry; use syntax::ast::NodeId; diff --git a/src/test/compile-fail/issue-12560-2.rs b/src/test/compile-fail/issue-12560-2.rs index 13829d73aad..9cbe2ebffe6 100644 --- a/src/test/compile-fail/issue-12560-2.rs +++ b/src/test/compile-fail/issue-12560-2.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z continue-parse-after-error + // For style and consistency reasons, non-parametrized enum variants must // be used simply as `ident` instead of `ident ()`. // This test-case covers enum matching. diff --git a/src/test/compile-fail/issue-28433.rs b/src/test/compile-fail/issue-28433.rs index 3ca2213087d..018a40e28ef 100644 --- a/src/test/compile-fail/issue-28433.rs +++ b/src/test/compile-fail/issue-28433.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z continue-parse-after-error + enum bird { pub duck, //~^ ERROR: expected identifier, found keyword `pub` diff --git a/src/test/compile-fail/issue-30715.rs b/src/test/compile-fail/issue-30715.rs index 67f619b4de4..5cacf8f53c6 100644 --- a/src/test/compile-fail/issue-30715.rs +++ b/src/test/compile-fail/issue-30715.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z continue-parse-after-error + macro_rules! parallel { ( // If future has `pred`/`moelarry` fragments (where "pred" is diff --git a/src/test/compile-fail/macro-incomplete-parse.rs b/src/test/compile-fail/macro-incomplete-parse.rs index 364a7e9cf6d..0d5f9079649 100644 --- a/src/test/compile-fail/macro-incomplete-parse.rs +++ b/src/test/compile-fail/macro-incomplete-parse.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z continue-parse-after-error + macro_rules! ignored_item { () => { fn foo() {} diff --git a/src/test/compile-fail/parse-error-correct.rs b/src/test/compile-fail/parse-error-correct.rs index 7715ed41841..17b58a9f7c2 100644 --- a/src/test/compile-fail/parse-error-correct.rs +++ b/src/test/compile-fail/parse-error-correct.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z continue-parse-after-error + // Test that the parser is error correcting missing idents. Despite a parsing // error (or two), we still run type checking (and don't get extra errors there). diff --git a/src/test/compile-fail/parser-recovery-1.rs b/src/test/compile-fail/parser-recovery-1.rs index 674418dcca6..85b62461238 100644 --- a/src/test/compile-fail/parser-recovery-1.rs +++ b/src/test/compile-fail/parser-recovery-1.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z continue-parse-after-error + // Test that we can recover from missing braces in the parser. trait Foo { diff --git a/src/test/compile-fail/parser-recovery-2.rs b/src/test/compile-fail/parser-recovery-2.rs index f1eb696f6ff..109da6251e3 100644 --- a/src/test/compile-fail/parser-recovery-2.rs +++ b/src/test/compile-fail/parser-recovery-2.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z continue-parse-after-error + // Test that we can recover from mismatched braces in the parser. trait Foo { diff --git a/src/test/compile-fail/self_type_keyword.rs b/src/test/compile-fail/self_type_keyword.rs index e28197e81fa..62966737874 100644 --- a/src/test/compile-fail/self_type_keyword.rs +++ b/src/test/compile-fail/self_type_keyword.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z continue-parse-after-error + struct Self; //~^ ERROR expected identifier, found keyword `Self` diff --git a/src/test/parse-fail/ascii-only-character-escape.rs b/src/test/parse-fail/ascii-only-character-escape.rs index 2094b63ab36..a8c40225c30 100644 --- a/src/test/parse-fail/ascii-only-character-escape.rs +++ b/src/test/parse-fail/ascii-only-character-escape.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error fn main() { let x = "\x80"; //~ ERROR may only be used diff --git a/src/test/parse-fail/bad-char-literals.rs b/src/test/parse-fail/bad-char-literals.rs index fe8ed8bb9a5..96311d6de17 100644 --- a/src/test/parse-fail/bad-char-literals.rs +++ b/src/test/parse-fail/bad-char-literals.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error // ignore-tidy-cr // ignore-tidy-tab diff --git a/src/test/parse-fail/bad-lit-suffixes.rs b/src/test/parse-fail/bad-lit-suffixes.rs index d5985fcebeb..0811a647024 100644 --- a/src/test/parse-fail/bad-lit-suffixes.rs +++ b/src/test/parse-fail/bad-lit-suffixes.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error extern diff --git a/src/test/parse-fail/byte-literals.rs b/src/test/parse-fail/byte-literals.rs index 3321f2450c1..3ecd7780afd 100644 --- a/src/test/parse-fail/byte-literals.rs +++ b/src/test/parse-fail/byte-literals.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error // ignore-tidy-tab diff --git a/src/test/parse-fail/byte-string-literals.rs b/src/test/parse-fail/byte-string-literals.rs index 22f123416f2..4eba9e91ca5 100644 --- a/src/test/parse-fail/byte-string-literals.rs +++ b/src/test/parse-fail/byte-string-literals.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error // ignore-tidy-tab diff --git a/src/test/parse-fail/issue-10412.rs b/src/test/parse-fail/issue-10412.rs index 0b9456bc080..b75e7b12bbd 100644 --- a/src/test/parse-fail/issue-10412.rs +++ b/src/test/parse-fail/issue-10412.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error trait Serializable<'self, T> { //~ ERROR no longer a special lifetime diff --git a/src/test/parse-fail/issue-23620-invalid-escapes.rs b/src/test/parse-fail/issue-23620-invalid-escapes.rs index d2f78ef897b..821149d1d00 100644 --- a/src/test/parse-fail/issue-23620-invalid-escapes.rs +++ b/src/test/parse-fail/issue-23620-invalid-escapes.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z parse-only -Z continue-parse-after-error + fn main() { let _ = b"\u{a66e}"; //~^ ERROR unicode escape sequences cannot be used as a byte or in a byte string diff --git a/src/test/parse-fail/lex-bad-binary-literal.rs b/src/test/parse-fail/lex-bad-binary-literal.rs index e92000c54ba..caacb12d008 100644 --- a/src/test/parse-fail/lex-bad-binary-literal.rs +++ b/src/test/parse-fail/lex-bad-binary-literal.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z parse-only -Z continue-parse-after-error + fn main() { 0b121; //~ ERROR invalid digit for a base 2 literal 0b10_10301; //~ ERROR invalid digit for a base 2 literal diff --git a/src/test/parse-fail/lex-bad-char-literals-1.rs b/src/test/parse-fail/lex-bad-char-literals-1.rs index 7e22a11ca97..006e3e68d8f 100644 --- a/src/test/parse-fail/lex-bad-char-literals-1.rs +++ b/src/test/parse-fail/lex-bad-char-literals-1.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error static c3: char = '\x1' //~ ERROR: numeric character escape is too short ; diff --git a/src/test/parse-fail/lex-bad-numeric-literals.rs b/src/test/parse-fail/lex-bad-numeric-literals.rs index cf171b694c3..bb97b037a00 100644 --- a/src/test/parse-fail/lex-bad-numeric-literals.rs +++ b/src/test/parse-fail/lex-bad-numeric-literals.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error fn main() { 0o1.0; //~ ERROR: octal float literal is not supported diff --git a/src/test/parse-fail/lex-bare-cr-string-literal-doc-comment.rs b/src/test/parse-fail/lex-bare-cr-string-literal-doc-comment.rs index aa48144650f..f8943057543 100644 --- a/src/test/parse-fail/lex-bare-cr-string-literal-doc-comment.rs +++ b/src/test/parse-fail/lex-bare-cr-string-literal-doc-comment.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error // ignore-tidy-cr diff --git a/src/test/parse-fail/new-unicode-escapes-4.rs b/src/test/parse-fail/new-unicode-escapes-4.rs index fe125da1755..5615ac8df01 100644 --- a/src/test/parse-fail/new-unicode-escapes-4.rs +++ b/src/test/parse-fail/new-unicode-escapes-4.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error pub fn main() { let s = "\u{lol}"; diff --git a/src/test/parse-fail/no-unsafe-self.rs b/src/test/parse-fail/no-unsafe-self.rs index 1cc0e62f5b2..cbdf50a7521 100644 --- a/src/test/parse-fail/no-unsafe-self.rs +++ b/src/test/parse-fail/no-unsafe-self.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error trait A { fn foo(*mut self); //~ ERROR cannot pass self by raw pointer