diff --git a/configure b/configure index fdef550a6451a..5273e4c03e722 100755 --- a/configure +++ b/configure @@ -609,6 +609,7 @@ opt llvm-version-check 1 "check if the LLVM version is supported, build anyway" opt rustbuild 0 "use the rust and cargo based build system" opt orbit 0 "get MIR where it belongs - everywhere; most importantly, in orbit" opt codegen-tests 1 "run the src/test/codegen tests" +opt option-checking 1 "complain about unrecognized options in this configure script" # Optimization and debugging options. These may be overridden by the release channel, etc. opt_nosave optimize 1 "build optimized rust code" @@ -674,8 +675,11 @@ then fi # Validate Options -step_msg "validating $CFG_SELF args" -validate_opt +if [ -z "$CFG_DISABLE_OPTION_CHECKING" ] +then + step_msg "validating $CFG_SELF args" + validate_opt +fi # Validate the release channel, and configure options case "$CFG_RELEASE_CHANNEL" in @@ -819,6 +823,19 @@ then fi fi +# LLDB tests on OSX require /usr/bin/python, not something like Homebrew's +# /usr/local/bin/python. We're loading a compiled module for LLDB tests which is +# only compatible with the system. +case $CFG_BUILD in + *-apple-darwin) + CFG_LLDB_PYTHON=/usr/bin/python + ;; + *) + CFG_LLDB_PYTHON=$CFG_PYTHON + ;; +esac +putvar CFG_LLDB_PYTHON + step_msg "looking for target specific programs" probe CFG_ADB adb diff --git a/mk/crates.mk b/mk/crates.mk index c55a6e791b68d..02b95f5b1a927 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -128,7 +128,7 @@ DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \ test rustc_lint rustc_const_eval -TOOL_DEPS_compiletest := test getopts log +TOOL_DEPS_compiletest := test getopts log serialize TOOL_DEPS_rustdoc := rustdoc TOOL_DEPS_rustc := rustc_driver TOOL_DEPS_rustbook := std rustdoc diff --git a/mk/tests.mk b/mk/tests.mk index dc7f9416a7cc1..1c65a09cbc4d1 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -619,7 +619,8 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ --stage-id stage$(1)-$(2) \ --target $(2) \ --host $(3) \ - --python $$(CFG_PYTHON) \ + --docck-python $$(CFG_PYTHON) \ + --lldb-python $$(CFG_LLDB_PYTHON) \ --gdb-version="$(CFG_GDB_VERSION)" \ --lldb-version="$(CFG_LLDB_VERSION)" \ --android-cross-path=$(CFG_ANDROID_CROSS_PATH) \ diff --git a/src/bootstrap/build/check.rs b/src/bootstrap/build/check.rs index f145a7149fbe1..32164080947a6 100644 --- a/src/bootstrap/build/check.rs +++ b/src/bootstrap/build/check.rs @@ -9,7 +9,8 @@ // except according to those terms. use std::fs; -use std::path::PathBuf; +use std::path::{PathBuf, Path}; +use std::process::Command; use build::{Build, Compiler}; @@ -81,8 +82,19 @@ pub fn compiletest(build: &Build, // FIXME: needs android support cmd.arg("--android-cross-path").arg(""); + // FIXME: CFG_PYTHON should probably be detected more robustly elsewhere - cmd.arg("--python").arg("python"); + let python_default = "python"; + cmd.arg("--docck-python").arg(python_default); + + if build.config.build.ends_with("apple-darwin") { + // Force /usr/bin/python on OSX for LLDB tests because we're loading the + // LLDB plugin's compiled module which only works with the system python + // (namely not Homebrew-installed python) + cmd.arg("--lldb-python").arg("/usr/bin/python"); + } else { + cmd.arg("--lldb-python").arg(python_default); + } if let Some(ref vers) = build.gdb_version { cmd.arg("--gdb-version").arg(vers); @@ -102,3 +114,42 @@ pub fn compiletest(build: &Build, build.run(&mut cmd); } + +pub fn docs(build: &Build, compiler: &Compiler) { + let mut stack = vec![build.src.join("src/doc")]; + + while let Some(p) = stack.pop() { + if p.is_dir() { + stack.extend(t!(p.read_dir()).map(|p| t!(p).path())); + continue + } + + if p.extension().and_then(|s| s.to_str()) != Some("md") { + continue + } + + println!("doc tests for: {}", p.display()); + markdown_test(build, compiler, &p); + } +} + +pub fn error_index(build: &Build, compiler: &Compiler) { + println!("Testing error-index stage{}", compiler.stage); + + let output = testdir(build, compiler.host).join("error-index.md"); + build.run(build.tool_cmd(compiler, "error_index_generator") + .arg("markdown") + .arg(&output) + .env("CFG_BUILD", &build.config.build)); + + markdown_test(build, compiler, &output); +} + +fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) { + let mut cmd = Command::new(build.rustdoc(compiler)); + build.add_rustc_lib_path(compiler, &mut cmd); + cmd.arg("--test"); + cmd.arg(markdown); + cmd.arg("--test-args").arg(build.flags.args.join(" ")); + build.run(&mut cmd); +} diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs index 4d4bff5b2f741..3c3add3d9a162 100644 --- a/src/bootstrap/build/mod.rs +++ b/src/bootstrap/build/mod.rs @@ -308,6 +308,12 @@ impl Build { check::compiletest(self, &compiler, target.target, "compile-fail", "compile-fail-fulldeps") } + CheckDocs { compiler } => { + check::docs(self, &compiler); + } + CheckErrorIndex { compiler } => { + check::error_index(self, &compiler); + } DistDocs { stage } => dist::docs(self, stage, target.target), DistMingw { _dummy } => dist::mingw(self, target.target), diff --git a/src/bootstrap/build/step.rs b/src/bootstrap/build/step.rs index e58ece0ab48ca..133ae702869a4 100644 --- a/src/bootstrap/build/step.rs +++ b/src/bootstrap/build/step.rs @@ -96,6 +96,8 @@ macro_rules! targets { (check_rpass_valgrind, CheckRPassValgrind { compiler: Compiler<'a> }), (check_rpass_full, CheckRPassFull { compiler: Compiler<'a> }), (check_cfail_full, CheckCFailFull { compiler: Compiler<'a> }), + (check_docs, CheckDocs { compiler: Compiler<'a> }), + (check_error_index, CheckErrorIndex { compiler: Compiler<'a> }), // Distribution targets, creating tarballs (dist, Dist { stage: u32 }), @@ -341,7 +343,10 @@ impl<'a> Step<'a> { self.check_rpass_valgrind(compiler), self.check_rpass_full(compiler), self.check_cfail_full(compiler), + self.check_error_index(compiler), + self.check_docs(compiler), self.check_linkcheck(stage), + self.check_tidy(stage), self.dist(stage), ] } @@ -383,6 +388,12 @@ impl<'a> Step<'a> { vec![self.librustc(compiler), self.tool_compiletest(compiler.stage)] } + Source::CheckDocs { compiler } => { + vec![self.libstd(compiler)] + } + Source::CheckErrorIndex { compiler } => { + vec![self.libstd(compiler), self.tool_error_index(compiler.stage)] + } Source::ToolLinkchecker { stage } | Source::ToolTidy { stage } => { diff --git a/src/doc/README.md b/src/doc/README.md index b5972f7ddb9ee..e1d95732b467c 100644 --- a/src/doc/README.md +++ b/src/doc/README.md @@ -9,7 +9,7 @@ libraries. To generate HTML documentation from one source file/crate, do something like: -~~~~ +~~~~text rustdoc --output html-doc/ --output-format html ../src/libstd/path.rs ~~~~ @@ -20,7 +20,7 @@ rustdoc --output html-doc/ --output-format html ../src/libstd/path.rs To generate an HTML version of a doc from Markdown manually, you can do something like: -~~~~ +~~~~text rustdoc reference.md ~~~~ diff --git a/src/doc/style/errors/ergonomics.md b/src/doc/style/errors/ergonomics.md index a404d25bf3703..269f2a289464a 100644 --- a/src/doc/style/errors/ergonomics.md +++ b/src/doc/style/errors/ergonomics.md @@ -9,7 +9,7 @@ pattern. Prefer -```rust +```rust,ignore use std::io::{File, Open, Write, IoError}; struct Info { @@ -31,7 +31,7 @@ fn write_info(info: &Info) -> Result<(), IoError> { over -```rust +```rust,ignore use std::io::{File, Open, Write, IoError}; struct Info { diff --git a/src/doc/style/features/functions-and-methods/README.md b/src/doc/style/features/functions-and-methods/README.md index 611cd564ccac7..a3559ca3e7b6b 100644 --- a/src/doc/style/features/functions-and-methods/README.md +++ b/src/doc/style/features/functions-and-methods/README.md @@ -4,7 +4,7 @@ Prefer -```rust +```rust,ignore impl Foo { pub fn frob(&self, w: widget) { ... } } @@ -12,7 +12,7 @@ impl Foo { over -```rust +```rust,ignore pub fn frob(foo: &Foo, w: widget) { ... } ``` diff --git a/src/doc/style/features/functions-and-methods/input.md b/src/doc/style/features/functions-and-methods/input.md index 9b243bc72ef71..5b63a4514443c 100644 --- a/src/doc/style/features/functions-and-methods/input.md +++ b/src/doc/style/features/functions-and-methods/input.md @@ -6,7 +6,7 @@ Prefer -```rust +```rust,ignore fn foo(b: Bar) { // use b as owned, directly } @@ -14,7 +14,7 @@ fn foo(b: Bar) { over -```rust +```rust,ignore fn foo(b: &Bar) { let b = b.clone(); // use b as owned after cloning @@ -33,13 +33,13 @@ needed, not as a way of signaling that copies should be cheap to make. Prefer -```rust +```rust,ignore fn foo(b: Bar) -> Bar { ... } ``` over -```rust +```rust,ignore fn foo(b: Box) -> Box { ... } ``` @@ -56,13 +56,13 @@ it becomes. Prefer -```rust +```rust,ignore fn foo>(c: T) { ... } ``` over any of -```rust +```rust,ignore fn foo(c: &[i32]) { ... } fn foo(c: &Vec) { ... } fn foo(c: &SomeOtherCollection) { ... } @@ -83,14 +83,14 @@ concrete nor overly abstract. See the discussion on Prefer either of -```rust +```rust,ignore fn foo(b: &Bar) { ... } fn foo(b: &mut Bar) { ... } ``` over -```rust +```rust,ignore fn foo(b: Bar) { ... } ``` @@ -101,13 +101,13 @@ ownership is actually needed. Prefer -```rust +```rust,ignore fn foo() -> (Bar, Bar) ``` over -```rust +```rust,ignore fn foo(output: &mut Bar) -> Bar ``` @@ -120,7 +120,7 @@ multiple values, it should do so via one of these types. The primary exception: sometimes a function is meant to modify data that the caller already owns, for example to re-use a buffer: -```rust +```rust,ignore fn read(&mut self, buf: &mut [u8]) -> std::io::Result ``` @@ -146,7 +146,7 @@ Choose an argument type that rules out bad inputs. For example, prefer -```rust +```rust,ignore enum FooMode { Mode1, Mode2, @@ -157,7 +157,7 @@ fn foo(mode: FooMode) { ... } over -```rust +```rust,ignore fn foo(mode2: bool, mode3: bool) { assert!(!mode2 || !mode3); ... diff --git a/src/doc/style/features/functions-and-methods/output.md b/src/doc/style/features/functions-and-methods/output.md index 3e43d1e416d76..e26eee53367cf 100644 --- a/src/doc/style/features/functions-and-methods/output.md +++ b/src/doc/style/features/functions-and-methods/output.md @@ -16,7 +16,7 @@ API. Prefer -```rust +```rust,ignore struct SearchResult { found: bool, // item in container? expected_index: usize // what would the item's index be? @@ -26,13 +26,13 @@ fn binary_search(&self, k: Key) -> SearchResult ``` or -```rust +```rust,ignore fn binary_search(&self, k: Key) -> (bool, usize) ``` over -```rust +```rust,ignore fn binary_search(&self, k: Key) -> bool ``` @@ -40,13 +40,13 @@ fn binary_search(&self, k: Key) -> bool Prefer -```rust +```rust,ignore fn from_utf8_owned(vv: Vec) -> Result> ``` over -```rust +```rust,ignore fn from_utf8_owned(vv: Vec) -> Option ``` diff --git a/src/doc/style/features/let.md b/src/doc/style/features/let.md index 01dff3dcceaf1..ba9787b45f13c 100644 --- a/src/doc/style/features/let.md +++ b/src/doc/style/features/let.md @@ -4,7 +4,7 @@ Prefer -```rust +```rust,ignore fn use_mutex(m: sync::mutex::Mutex) { let guard = m.lock(); do_work(guard); @@ -15,7 +15,7 @@ fn use_mutex(m: sync::mutex::Mutex) { over -```rust +```rust,ignore fn use_mutex(m: sync::mutex::Mutex) { do_work(m.lock()); // do other work @@ -32,7 +32,7 @@ explicitly `let`-bound to make the lifetime clear. Consider using an explicit Prefer -```rust +```rust,ignore let foo = match bar { Baz => 0, Quux => 1 @@ -41,7 +41,7 @@ let foo = match bar { over -```rust +```rust,ignore let foo; match bar { Baz => { @@ -60,14 +60,14 @@ conditional expression. Prefer -```rust +```rust,ignore let v = s.iter().map(|x| x * 2) .collect::>(); ``` over -```rust +```rust,ignore let v: Vec<_> = s.iter().map(|x| x * 2) .collect(); ``` @@ -87,7 +87,7 @@ the type by explicit generics instantiation, which is usually more clear. Use `mut` bindings to signal the span during which a value is mutated: -```rust +```rust,ignore let mut v = Vec::new(); // push things onto v let v = v; diff --git a/src/doc/style/features/match.md b/src/doc/style/features/match.md index 131e0fad79a92..0d5a1184a0e87 100644 --- a/src/doc/style/features/match.md +++ b/src/doc/style/features/match.md @@ -4,7 +4,7 @@ Prefer -~~~~ +~~~~ignore match *foo { X(...) => ... Y(...) => ... @@ -13,7 +13,7 @@ match *foo { over -~~~~ +~~~~ignore match foo { box X(...) => ... box Y(...) => ... diff --git a/src/doc/style/features/modules.md b/src/doc/style/features/modules.md index c55b38b915b3d..995c5fda8a0aa 100644 --- a/src/doc/style/features/modules.md +++ b/src/doc/style/features/modules.md @@ -35,7 +35,7 @@ module hierarchy match, instead. For all except very short modules (<100 lines) and [tests](../testing/README.md), place the module `foo` in a separate file, as in: -```rust +```rust,ignore pub mod foo; // in foo.rs or foo/mod.rs @@ -45,7 +45,7 @@ pub fn bar() { println!("..."); } rather than declaring it inline: -```rust +```rust,ignore pub mod foo { pub fn bar() { println!("..."); } /* ... */ @@ -67,7 +67,7 @@ On the other hand, [`io::net`](https://doc.rust-lang.org/std/io/net/) contains submodules, so it lives in a separate directory: -``` +```text io/mod.rs io/extensions.rs io/fs.rs @@ -120,7 +120,7 @@ and [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html), but these are re-exported in `io/mod.rs` at the top level of the module: -```rust +```rust,ignore // libstd/io/mod.rs pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter}; diff --git a/src/doc/style/features/traits/common.md b/src/doc/style/features/traits/common.md index 18346c092547f..e8699c75229d3 100644 --- a/src/doc/style/features/traits/common.md +++ b/src/doc/style/features/traits/common.md @@ -19,7 +19,7 @@ workaround; see [newtype for views](../types/newtype.md)) The most important common traits to implement from `std` are: -```rust +```text Clone, Debug, Hash, Eq ``` diff --git a/src/doc/style/features/traits/generics.md b/src/doc/style/features/traits/generics.md index a09640c3055c2..f9dac1272c334 100644 --- a/src/doc/style/features/traits/generics.md +++ b/src/doc/style/features/traits/generics.md @@ -4,7 +4,7 @@ The most widespread use of traits is for writing generic functions or types. For example, the following signature describes a function for consuming any iterator yielding items of type `A` to produce a collection of `A`: -```rust +```rust,ignore fn from_iter>(iterator: T) -> SomeCollection ``` @@ -32,7 +32,7 @@ explicitly implement to be used by this generic function. implementing a trait, it is possible to be precise about places where that exact type is required or produced. For example, a function - ```rust + ```rust,ignore fn binary(x: T, y: T) -> T ``` diff --git a/src/doc/style/features/traits/objects.md b/src/doc/style/features/traits/objects.md index 38494a9b9bc3c..34712ed1ae7f1 100644 --- a/src/doc/style/features/traits/objects.md +++ b/src/doc/style/features/traits/objects.md @@ -6,7 +6,7 @@ Trait objects are useful primarily when _heterogeneous_ collections of objects need to be treated uniformly; it is the closest that Rust comes to object-oriented programming. -```rust +```rust,ignore struct Frame { ... } struct Button { ... } struct Label { ... } diff --git a/src/doc/style/features/types/README.md b/src/doc/style/features/types/README.md index c675eb581c6ae..d3b95d8a6e719 100644 --- a/src/doc/style/features/types/README.md +++ b/src/doc/style/features/types/README.md @@ -4,13 +4,13 @@ Prefer -```rust +```rust,ignore let w = Widget::new(Small, Round) ``` over -```rust +```rust,ignore let w = Widget::new(true, false) ``` diff --git a/src/doc/style/features/types/newtype.md b/src/doc/style/features/types/newtype.md index e69aa3b83bfa4..9646e3e82aa53 100644 --- a/src/doc/style/features/types/newtype.md +++ b/src/doc/style/features/types/newtype.md @@ -13,7 +13,7 @@ underlying type. For example, a `f64` value might be used to represent a quantity in miles or in kilometers. Using newtypes, we can keep track of the intended interpretation: -```rust +```rust,ignore struct Miles(pub f64); struct Kilometers(pub f64); @@ -28,7 +28,7 @@ impl Kilometers { Once we have separated these two types, we can statically ensure that we do not confuse them. For example, the function -```rust +```rust,ignore fn are_we_there_yet(distance_travelled: Miles) -> bool { ... } ``` @@ -46,7 +46,7 @@ type `Enumerate>>`. We wish to hide this type from the client, so that the client's view of the return type is roughly `Iterator<(usize, T)>`. We can do so using the newtype pattern: -```rust +```rust,ignore struct MyTransformResult(Enumerate>>); impl Iterator<(usize, T)> for MyTransformResult { ... } diff --git a/src/doc/style/ownership/builders.md b/src/doc/style/ownership/builders.md index 9fc640890fe8a..3422591233275 100644 --- a/src/doc/style/ownership/builders.md +++ b/src/doc/style/ownership/builders.md @@ -35,7 +35,7 @@ be consumed. The follow variant on [`std::process::Command`](https://doc.rust-lang.org/stable/std/process/struct.Command.html) is one example: -```rust +```rust,ignore // NOTE: the actual Command API does not use owned Strings; // this is a simplified version. @@ -94,7 +94,7 @@ methods take and return a mutable borrow of `self`. By using borrows throughout, `Command` can be used conveniently for both one-liner and more complex constructions: -```rust +```rust,ignore // One-liners Command::new("/bin/cat").arg("file.txt").spawn(); @@ -114,7 +114,7 @@ cmd.spawn(); Sometimes builders must transfer ownership when constructing the final type `T`, meaning that the terminal methods must take `self` rather than `&self`: -```rust +```rust,ignore // A simplified excerpt from std::thread::Builder impl ThreadBuilder { @@ -156,7 +156,7 @@ Under the rubric of making easy things easy and hard things possible, _all_ builder methods for a consuming builder should take and returned an owned `self`. Then client code works as follows: -```rust +```rust,ignore // One-liners ThreadBuilder::new().named("my_thread").spawn(proc() { ... }); diff --git a/src/doc/style/ownership/constructors.md b/src/doc/style/ownership/constructors.md index b4a1147315679..51fc74ac1158a 100644 --- a/src/doc/style/ownership/constructors.md +++ b/src/doc/style/ownership/constructors.md @@ -4,7 +4,7 @@ In Rust, "constructors" are just a convention: -```rust +```rust,ignore impl Vec { pub fn new() -> Vec { ... } } @@ -15,7 +15,7 @@ construct. Combined with the practice of [fully importing type names](../style/imports.md), this convention leads to informative but concise construction: -```rust +```rust,ignore use vec::Vec; // construct a new vector @@ -29,7 +29,7 @@ than `new`). Given the `struct` -```rust +```rust,ignore pub struct Config { pub color: Color, pub size: Size, @@ -39,7 +39,7 @@ pub struct Config { provide a constructor if there are sensible defaults: -```rust +```rust,ignore impl Config { pub fn new() -> Config { Config { @@ -53,7 +53,7 @@ impl Config { which then allows clients to concisely override using `struct` update syntax: -```rust +```rust,ignore Config { color: Red, .. Config::new() }; ``` diff --git a/src/doc/style/style/braces.md b/src/doc/style/style/braces.md index 0f61bac9fd229..80323dba1d4c2 100644 --- a/src/doc/style/style/braces.md +++ b/src/doc/style/style/braces.md @@ -2,7 +2,7 @@ ### Opening braces always go on the same line. -``` rust +```rust,ignore fn foo() { ... } @@ -30,7 +30,7 @@ frob(|x| { ### `match` arms get braces, except for single-line expressions. -``` rust +```rust,ignore match foo { bar => baz, quux => { @@ -42,7 +42,7 @@ match foo { ### `return` statements get semicolons. -``` rust +```rust,ignore fn foo() { do_something(); @@ -62,7 +62,7 @@ fn foo() { > One possible rule: a trailing comma should be included whenever the > closing delimiter appears on a separate line: -```rust +```rust,ignore Foo { bar: 0, baz: 1 } Foo { diff --git a/src/doc/style/style/comments.md b/src/doc/style/style/comments.md index 3851187b52034..bf8cf653dbb16 100644 --- a/src/doc/style/style/comments.md +++ b/src/doc/style/style/comments.md @@ -4,7 +4,7 @@ Use line comments: -``` rust +```rust // Wait for the main thread to return, and set the process error code // appropriately. ``` @@ -51,7 +51,7 @@ Basically, this means write "Returns" instead of "Return". For example: -``` rust +```rust,ignore /// Sets up a default runtime configuration, given compiler-supplied arguments. /// /// This function will block until the entire pool of M:N schedulers has @@ -80,7 +80,7 @@ For example: Use inner doc comments _only_ to document crates and file-level modules: -``` rust +```rust,ignore //! The core library. //! //! The core library is a something something... @@ -92,7 +92,7 @@ Rust doesn't have special constructors, only functions that return new instances. These aren't visible in the automatically generated documentation for a type, so you should specifically link to them: -``` rust +```rust,ignore /// An iterator that yields `None` forever after the underlying iterator /// yields `None` once. /// diff --git a/src/doc/style/style/features.md b/src/doc/style/style/features.md index b5d0b484ccda5..578270fbdc256 100644 --- a/src/doc/style/style/features.md +++ b/src/doc/style/style/features.md @@ -2,7 +2,7 @@ Terminate `return` statements with semicolons: -``` rust +``` rust,ignore fn foo(bar: i32) -> Option { if some_condition() { return None; diff --git a/src/doc/style/style/imports.md b/src/doc/style/style/imports.md index cf3fd4163a26e..c958875ddb926 100644 --- a/src/doc/style/style/imports.md +++ b/src/doc/style/style/imports.md @@ -10,7 +10,7 @@ sections, in order, with a blank space between each: For example: -```rust +```rust,ignore // Crates. extern crate getopts; extern crate mylib; @@ -40,7 +40,7 @@ as a convenience. For example: -```rust +```rust,ignore use option::Option; use mem; diff --git a/src/doc/style/style/naming/README.md b/src/doc/style/style/naming/README.md index 2106f32fafade..6d88a838f5f53 100644 --- a/src/doc/style/style/naming/README.md +++ b/src/doc/style/style/naming/README.md @@ -69,7 +69,7 @@ Names of items within a module should not be prefixed with that module's name: Prefer -``` rust +```rust,ignore mod foo { pub struct Error { ... } } @@ -77,7 +77,7 @@ mod foo { over -``` rust +```rust,ignore mod foo { pub struct FooError { ... } } diff --git a/src/doc/style/style/naming/containers.md b/src/doc/style/style/naming/containers.md index dfed4f9f75a58..c352a5b1bf191 100644 --- a/src/doc/style/style/naming/containers.md +++ b/src/doc/style/style/naming/containers.md @@ -13,7 +13,7 @@ appropriate. This name is chosen rather than names like `find` or For a container with keys/indexes of type `K` and elements of type `V`: -```rust +```rust,ignore // Look up element without failing fn get(&self, key: K) -> Option<&V> fn get_mut(&mut self, key: K) -> Option<&mut V> @@ -31,7 +31,7 @@ impl IndexMut for Container { ... } Prefer specific conversion functions like `as_bytes` or `into_vec` whenever possible. Otherwise, use: -```rust +```rust,ignore // Extract contents without failing fn get(&self) -> &V fn get_mut(&mut self) -> &mut V @@ -40,7 +40,7 @@ fn unwrap(self) -> V #### Wrappers/Cells around `Copy` data -```rust +```rust,ignore // Extract contents without failing fn get(&self) -> V ``` @@ -52,7 +52,7 @@ play a special role for failure. For `Option`: -```rust +```rust,ignore // Extract contents or fail if not available fn assert(self) -> V fn expect(self, &str) -> V @@ -60,7 +60,7 @@ fn expect(self, &str) -> V For `Result`: -```rust +```rust,ignore // Extract the contents of Ok variant; fail if Err fn assert(self) -> V diff --git a/src/doc/style/style/naming/iterators.md b/src/doc/style/style/naming/iterators.md index 38138b5e39d3a..945cbe4800cb0 100644 --- a/src/doc/style/style/naming/iterators.md +++ b/src/doc/style/style/naming/iterators.md @@ -6,7 +6,7 @@ For a container with elements of type `U`, iterator methods should be named: -```rust +```rust,ignore fn iter(&self) -> T // where T implements Iterator<&U> fn iter_mut(&mut self) -> T // where T implements Iterator<&mut U> fn into_iter(self) -> T // where T implements Iterator diff --git a/src/doc/style/style/whitespace.md b/src/doc/style/style/whitespace.md index c28a723209563..c33c17c8e42a2 100644 --- a/src/doc/style/style/whitespace.md +++ b/src/doc/style/style/whitespace.md @@ -8,7 +8,7 @@ * Use spaces around binary operators, including the equals sign in attributes: -``` rust +```rust,ignore #[deprecated = "Use `bar` instead."] fn foo(a: usize, b: usize) -> usize { a + b @@ -17,7 +17,7 @@ fn foo(a: usize, b: usize) -> usize { * Use a space after colons and commas: -``` rust +```rust,ignore fn foo(a: Bar); MyStruct { foo: 3, bar: 4 } @@ -28,7 +28,7 @@ foo(bar, baz); * Use a space after the opening and before the closing brace for single line blocks or `struct` expressions: -``` rust +```rust,ignore spawn(proc() { do_something(); }) Point { x: 0.1, y: 0.3 } @@ -39,7 +39,7 @@ Point { x: 0.1, y: 0.3 } * For multiline function signatures, each new line should align with the first parameter. Multiple parameters per line are permitted: -``` rust +```rust,ignore fn frobnicate(a: Bar, b: Bar, c: Bar, d: Bar) -> Bar { @@ -59,7 +59,7 @@ fn foo Bar { ... @@ -77,7 +77,7 @@ foo_bar(x, y, |z| { > **[FIXME]** Do we also want to allow the following? > -> ```rust +> ```rust,ignore > frobnicate( > arg1, > arg2, @@ -92,7 +92,7 @@ foo_bar(x, y, |z| { > * **[Deprecated]** If you have multiple patterns in a single `match` > arm, write each pattern on a separate line: > -> ``` rust +> ```rust,ignore > match foo { > bar(_) > | baz => quux, @@ -110,7 +110,7 @@ Idiomatic code should not use extra whitespace in the middle of a line to provide alignment. -``` rust +```rust,ignore // Good struct Foo { short: f64, diff --git a/src/etc/lldb_batchmode.py b/src/etc/lldb_batchmode.py index b1506285b3ac1..7bbb3577f8d93 100644 --- a/src/etc/lldb_batchmode.py +++ b/src/etc/lldb_batchmode.py @@ -216,4 +216,5 @@ def watchdog(): print("Aborting.", file=sys.stderr) sys.exit(1) finally: + debugger.Terminate() script_file.close() diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index aa7ab4b4e3f85..dc01a9b5c7803 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -15,7 +15,6 @@ #![feature(box_syntax)] #![feature(cell_extras)] #![feature(const_fn)] -#![feature(core_float)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] #![feature(dec2flt)] diff --git a/src/libcoretest/num/mod.rs b/src/libcoretest/num/mod.rs index 11c1bd667fb36..d5a6e0f87d69b 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcoretest/num/mod.rs @@ -52,7 +52,6 @@ pub fn test_num(ten: T, two: T) where mod tests { use core::option::Option; use core::option::Option::{Some, None}; - use core::num::Float; #[test] fn from_str_issue7588() { diff --git a/src/librand/distributions/exponential.rs b/src/librand/distributions/exponential.rs index f02b945178fb9..12dbbfdb0ed4d 100644 --- a/src/librand/distributions/exponential.rs +++ b/src/librand/distributions/exponential.rs @@ -10,6 +10,7 @@ //! The exponential distribution. +#[cfg(not(test))] // only necessary for no_std use FloatMath; use {Rng, Rand}; diff --git a/src/librand/distributions/gamma.rs b/src/librand/distributions/gamma.rs index 8cd7ac06f991b..cf48823656044 100644 --- a/src/librand/distributions/gamma.rs +++ b/src/librand/distributions/gamma.rs @@ -13,6 +13,7 @@ use self::GammaRepr::*; use self::ChiSquaredRepr::*; +#[cfg(not(test))] // only necessary for no_std use FloatMath; use {Rng, Open01}; diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs index a54c8df2352ac..2557d39c550f5 100644 --- a/src/librand/distributions/mod.rs +++ b/src/librand/distributions/mod.rs @@ -17,7 +17,9 @@ //! internally. The `IndependentSample` trait is for generating values //! that do not need to record state. +#[cfg(not(test))] // only necessary for no_std use core::num::Float; + use core::marker::PhantomData; use {Rng, Rand}; diff --git a/src/librand/distributions/normal.rs b/src/librand/distributions/normal.rs index b2ccc5eb6095b..86840c568e018 100644 --- a/src/librand/distributions/normal.rs +++ b/src/librand/distributions/normal.rs @@ -10,6 +10,7 @@ //! The normal and derived distributions. +#[cfg(not(test))] // only necessary for no_std use FloatMath; use {Rng, Rand, Open01}; diff --git a/src/librand/lib.rs b/src/librand/lib.rs index e651f5bc1829b..d8517fb4c5714 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -28,13 +28,13 @@ #![unstable(feature = "rand", reason = "use `rand` from crates.io", issue = "27703")] -#![feature(core_float)] #![feature(core_intrinsics)] #![feature(staged_api)] #![feature(step_by)] #![feature(custom_attribute)] #![allow(unused_attributes)] +#![cfg_attr(not(test), feature(core_float))] // only necessary for no_std #![cfg_attr(test, feature(test, rand))] #![allow(deprecated)] diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 536c739bf1615..8732df1437153 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -59,6 +59,7 @@ pub enum DepNode { TypeckItemBody(D), Dropck, DropckImpl(D), + UnusedTraitCheck, CheckConst(D), Privacy, IntrinsicCheck(D), @@ -163,6 +164,7 @@ impl DepNode { CheckEntryFn => Some(CheckEntryFn), Variance => Some(Variance), Dropck => Some(Dropck), + UnusedTraitCheck => Some(UnusedTraitCheck), Privacy => Some(Privacy), Reachability => Some(Reachability), DeadCheck => Some(DeadCheck), diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 4e7520035238f..b60524388d3c6 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1637,8 +1637,13 @@ pub type FreevarMap = NodeMap>; pub type CaptureModeMap = NodeMap; +pub struct TraitCandidate { + pub def_id: DefId, + pub import_id: Option, +} + // Trait method resolution -pub type TraitMap = NodeMap>; +pub type TraitMap = NodeMap>; // Map from the NodeId of a glob import to a list of items which are actually // imported. diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 96acb708315e4..312a446d44091 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -35,7 +35,7 @@ use ty::fold::TypeFoldable; use ty::relate::{Relate, RelateResult, TypeRelation}; use traits::{self, PredicateObligations, ProjectionMode}; use rustc_data_structures::unify::{self, UnificationTable}; -use std::cell::{RefCell, Ref}; +use std::cell::{Cell, RefCell, Ref}; use std::fmt; use syntax::ast; use syntax::codemap; @@ -110,6 +110,25 @@ pub struct InferCtxt<'a, 'tcx: 'a> { // documentation for `ProjectionMode`. projection_mode: ProjectionMode, + // When an error occurs, we want to avoid reporting "derived" + // errors that are due to this original failure. Normally, we + // handle this with the `err_count_on_creation` count, which + // basically just tracks how many errors were reported when we + // started type-checking a fn and checks to see if any new errors + // have been reported since then. Not great, but it works. + // + // However, when errors originated in other passes -- notably + // resolve -- this heuristic breaks down. Therefore, we have this + // auxiliary flag that one can set whenever one creates a + // type-error that is due to an error in a prior pass. + // + // Don't read this flag directly, call `is_tainted_by_errors()` + // and `set_tainted_by_errors()`. + tainted_by_errors_flag: Cell, + + // Track how many errors were reported when this infcx is created. + // If the number of errors increases, that's also a sign (line + // `tained_by_errors`) to avoid reporting certain kinds of errors. err_count_on_creation: usize, } @@ -379,6 +398,7 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>, reported_trait_errors: RefCell::new(FnvHashSet()), normalize: false, projection_mode: projection_mode, + tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count() } } @@ -1128,15 +1148,36 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .map(|method| resolve_ty(method.ty))) } - pub fn errors_since_creation(&self) -> bool { - self.tcx.sess.err_count() - self.err_count_on_creation != 0 + /// True if errors have been reported since this infcx was + /// created. This is sometimes used as a heuristic to skip + /// reporting errors that often occur as a result of earlier + /// errors, but where it's hard to be 100% sure (e.g., unresolved + /// inference variables, regionck errors). + pub fn is_tainted_by_errors(&self) -> bool { + debug!("is_tainted_by_errors(err_count={}, err_count_on_creation={}, \ + tainted_by_errors_flag={})", + self.tcx.sess.err_count(), + self.err_count_on_creation, + self.tainted_by_errors_flag.get()); + + if self.tcx.sess.err_count() > self.err_count_on_creation { + return true; // errors reported since this infcx was made + } + self.tainted_by_errors_flag.get() + } + + /// Set the "tainted by errors" flag to true. We call this when we + /// observe an error from a prior pass. + pub fn set_tainted_by_errors(&self) { + debug!("set_tainted_by_errors()"); + self.tainted_by_errors_flag.set(true) } pub fn node_type(&self, id: ast::NodeId) -> Ty<'tcx> { match self.tables.borrow().node_types.get(&id) { Some(&t) => t, // FIXME - None if self.errors_since_creation() => + None if self.is_tainted_by_errors() => self.tcx.types.err, None => { bug!("no type for node {}: {} in fcx", @@ -1158,7 +1199,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { free_regions: &FreeRegionMap, subject_node_id: ast::NodeId) { let errors = self.region_vars.resolve_regions(free_regions, subject_node_id); - if !self.errors_since_creation() { + if !self.is_tainted_by_errors() { // As a heuristic, just skip reporting region errors // altogether if other errors have been reported while // this infcx was in use. This is totally hokey but diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index ece8c0c696af8..71e1efe220f03 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -91,6 +91,7 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> { } (&ty::TyError, _) | (_, &ty::TyError) => { + infcx.set_tainted_by_errors(); Ok(self.tcx().types.err) } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 3b5bdd734b4ce..d7ddfc9f1a6d0 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -624,6 +624,12 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, predicate, obligation); + // Ambiguity errors are often caused as fallout from earlier + // errors. So just ignore them if this infcx is tainted. + if infcx.is_tainted_by_errors() { + return; + } + match predicate { ty::Predicate::Trait(ref data) => { let trait_ref = data.to_poly_trait_ref(); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 10000607b5409..21ce86e334d7a 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -289,6 +289,8 @@ pub struct TyCtxt<'tcx> { // scratch every time. pub freevars: RefCell, + pub maybe_unused_trait_imports: NodeSet, + // Records the type of every item. pub tcache: RefCell>>, @@ -338,6 +340,10 @@ pub struct TyCtxt<'tcx> { /// about. pub used_mut_nodes: RefCell, + /// Set of trait imports actually used in the method resolution. + /// This is used for warning unused imports. + pub used_trait_imports: RefCell, + /// The set of external nominal types whose implementations have been read. /// This is used for lazy resolution of methods. pub populated_external_types: RefCell, @@ -543,6 +549,7 @@ impl<'tcx> TyCtxt<'tcx> { named_region_map: resolve_lifetime::NamedRegionMap, map: ast_map::Map<'tcx>, freevars: FreevarMap, + maybe_unused_trait_imports: NodeSet, region_maps: RegionMaps, lang_items: middle::lang_items::LanguageItems, stability: stability::Index<'tcx>, @@ -581,6 +588,7 @@ impl<'tcx> TyCtxt<'tcx> { fulfilled_predicates: RefCell::new(fulfilled_predicates), map: map, freevars: RefCell::new(freevars), + maybe_unused_trait_imports: maybe_unused_trait_imports, tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), rcache: RefCell::new(FnvHashMap()), tc_cache: RefCell::new(FnvHashMap()), @@ -595,6 +603,7 @@ impl<'tcx> TyCtxt<'tcx> { impl_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), used_unsafe: RefCell::new(NodeSet()), used_mut_nodes: RefCell::new(NodeSet()), + used_trait_imports: RefCell::new(NodeSet()), populated_external_types: RefCell::new(DefIdSet()), populated_external_primitive_impls: RefCell::new(DefIdSet()), extern_const_statics: RefCell::new(DefIdMap()), diff --git a/src/librustc_back/sha2.rs b/src/librustc_back/sha2.rs index ba8107e03c9f7..55a6b4739f441 100644 --- a/src/librustc_back/sha2.rs +++ b/src/librustc_back/sha2.rs @@ -531,7 +531,7 @@ mod tests { use self::rand::isaac::IsaacRng; use serialize::hex::FromHex; use std::u64; - use super::{Digest, Sha256, FixedBuffer}; + use super::{Digest, Sha256}; // A normal addition - no overflow occurs #[test] @@ -648,7 +648,7 @@ mod tests { mod bench { extern crate test; use self::test::Bencher; - use super::{Sha256, FixedBuffer, Digest}; + use super::{Sha256, Digest}; #[bench] pub fn sha256_10(b: &mut Bencher) { diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 3f68f6aeccace..638ed4bf7bb96 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -17,7 +17,7 @@ use self::EvalHint::*; use rustc::hir::map as ast_map; use rustc::hir::map::blocks::FnLikeNode; -use rustc::middle::cstore::{self, CrateStore, InlinedItem}; +use rustc::middle::cstore::{self, InlinedItem}; use rustc::{infer, traits}; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 5fc2a955c0602..800abad3d44ef 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -777,6 +777,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let resolve::CrateMap { def_map, freevars, + maybe_unused_trait_imports, export_map, trait_map, glob_map, @@ -826,6 +827,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, named_region_map, hir_map, freevars, + maybe_unused_trait_imports, region_map, lang_items, index, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 0e100f48ac38d..990ec490d1c2d 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -69,7 +69,6 @@ use rustc_trans::back::link; use rustc::session::{config, Session, build_session, CompileResult}; use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType}; use rustc::session::config::{get_unstable_features_setting, nightly_options}; -use rustc::middle::cstore::CrateStore; use rustc::lint::Lint; use rustc::lint; use rustc_metadata::loader; diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index ce92dd158c969..aa2588381246e 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -24,7 +24,6 @@ use rustc::ty::subst; use rustc::ty::subst::Subst; use rustc::traits::ProjectionMode; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::ty::relate::TypeRelation; use rustc::infer::{self, InferOk, InferResult, TypeOrigin}; use rustc_metadata::cstore::CStore; use rustc_metadata::creader::LocalCrateReader; @@ -133,7 +132,7 @@ fn test_env(source_string: &str, // run just enough stuff to build a tcx: let lang_items = lang_items::collect_language_items(&sess, &ast_map); - let resolve::CrateMap { def_map, freevars, .. } = + let resolve::CrateMap { def_map, freevars, maybe_unused_trait_imports, .. } = resolve::resolve_crate(&sess, &ast_map, resolve::MakeGlobMap::No); let named_region_map = resolve_lifetime::krate(&sess, &ast_map, &def_map.borrow()); let region_map = region::resolve_crate(&sess, &ast_map); @@ -144,6 +143,7 @@ fn test_env(source_string: &str, named_region_map.unwrap(), ast_map, freevars, + maybe_unused_trait_imports, region_map, lang_items, index, diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index 60d644ba7681a..37d5f8937f174 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -11,7 +11,6 @@ //! The data that we will serialize and deserialize. use rustc::dep_graph::DepNode; -use rustc_serialize::{Decoder as RustcDecoder, Encoder as RustcEncoder}; use super::directory::DefPathIndex; diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs index 7f4c7d919c0cb..796812556d2a7 100644 --- a/src/librustc_incremental/persist/directory.rs +++ b/src/librustc_incremental/persist/directory.rs @@ -18,7 +18,6 @@ use rustc::hir::map::DefPath; use rustc::hir::def_id::DefId; use rustc::ty; use rustc::util::nodemap::DefIdMap; -use rustc_serialize::{Decoder as RustcDecoder, Encoder as RustcEncoder}; use std::fmt::{self, Debug}; /// Index into the DefIdDirectory diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 5e3a47701ebbf..8f9ae2ef41980 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -29,7 +29,6 @@ //! a `pub fn new()`. use rustc::hir::def::Def; -use middle::cstore::CrateStore; use rustc::hir::def_id::DefId; use middle::stability; use rustc::{cfg, infer}; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 891731cb29604..b81a4a0efe741 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -26,7 +26,7 @@ use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; use syntax::ast; use syntax::abi::Abi; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::codemap::{self, Span}; use rustc::hir; diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 8e7be0e3a0f5e..6a79d5df80ae2 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -536,7 +536,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { let mut visible_parent_map = self.visible_parent_map.borrow_mut(); if !visible_parent_map.is_empty() { return visible_parent_map; } - use rustc::middle::cstore::{CrateStore, ChildItem}; + use rustc::middle::cstore::ChildItem; use std::collections::vec_deque::VecDeque; use std::collections::hash_map::Entry; for cnum in 1 .. self.next_crate_num() { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b5b27586a7f76..58bc4e2a193fa 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -43,7 +43,6 @@ use rustc::mir; use rustc::mir::visit::MutVisitor; use std::cell::Cell; -use std::io::prelude::*; use std::io; use std::rc::Rc; use std::str; diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 40a7f91154f97..7558e0774b362 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -21,7 +21,7 @@ use def_key; use tyencode; use index::{self, IndexData}; -use middle::cstore::{LOCAL_CRATE, CrateStore, InlinedItemRef, LinkMeta, tls}; +use middle::cstore::{LOCAL_CRATE, InlinedItemRef, LinkMeta, tls}; use rustc::hir::def; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::dependency_format::Linkage; @@ -46,7 +46,6 @@ use syntax::abi::Abi; use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum}; use syntax::codemap::BytePos; use syntax::attr; -use syntax::attr::AttrMetaMethods; use syntax::errors::Handler; use syntax; use rbml::writer::Encoder; diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 28e0e5746a3ee..6b30133fe49a4 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -233,7 +233,6 @@ use std::cmp; use std::collections::HashMap; use std::fmt; use std::fs; -use std::io::prelude::*; use std::io; use std::path::{Path, PathBuf}; use std::ptr; diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index d55d0d53b8c48..4a4b7caf478ea 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -34,7 +34,6 @@ use rustc::hir::intravisit::{self, Visitor}; use rustc::dep_graph::DepNode; use rustc::lint; -use rustc::middle::cstore::CrateStore; use rustc::hir::def::{self, Def}; use rustc::hir::def_id::DefId; use rustc::middle::privacy::{AccessLevel, AccessLevels}; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index effc751c50759..c2106b7c51a20 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -21,7 +21,7 @@ use ParentLink::{ModuleParentLink, BlockParentLink}; use Resolver; use {resolve_error, resolve_struct_error, ResolutionError}; -use rustc::middle::cstore::{CrateStore, ChildItem, DlDef}; +use rustc::middle::cstore::{ChildItem, DlDef}; use rustc::lint; use rustc::hir::def::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 9135b656736a2..e213a51fb3842 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -16,6 +16,8 @@ // resolve data structures and because it finalises the privacy information for // `use` directives. // +// Unused trait imports can't be checked until the method resolution. We save +// candidates here, and do the acutal check in librustc_typeck/check_unused.rs. use std::ops::{Deref, DerefMut}; @@ -55,10 +57,18 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> { fn check_import(&mut self, id: ast::NodeId, span: Span) { if !self.used_imports.contains(&(id, TypeNS)) && !self.used_imports.contains(&(id, ValueNS)) { + if self.maybe_unused_trait_imports.contains(&id) { + // Check later. + return; + } self.session.add_lint(lint::builtin::UNUSED_IMPORTS, id, span, "unused import".to_string()); + } else { + // This trait import is definitely used, in a way other than + // method resolution. + self.maybe_unused_trait_imports.remove(&id); } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8326b8b95e996..170ac5d01373c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -48,18 +48,16 @@ use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use rustc::session::Session; use rustc::lint; -use rustc::middle::cstore::CrateStore; use rustc::hir::def::*; use rustc::hir::def_id::DefId; use rustc::hir::pat_util::pat_bindings; use rustc::ty; use rustc::ty::subst::{ParamSpace, FnSpace, TypeSpace}; -use rustc::hir::{Freevar, FreevarMap, TraitMap, GlobMap}; -use rustc::util::nodemap::{NodeMap, FnvHashMap, FnvHashSet}; +use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; +use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; use syntax::ast::{self, FloatTy}; use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; -use syntax::attr::AttrMetaMethods; use syntax::codemap::{self, Span, Pos}; use syntax::errors::DiagnosticBuilder; use syntax::parse::token::{self, special_names, special_idents}; @@ -1093,6 +1091,7 @@ pub struct Resolver<'a, 'tcx: 'a> { used_imports: HashSet<(NodeId, Namespace)>, used_crates: HashSet, + maybe_unused_trait_imports: NodeSet, // Callback function for intercepting walks callback: Option bool>>, @@ -1183,13 +1182,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { export_map: NodeMap(), trait_map: NodeMap(), module_map: NodeMap(), - used_imports: HashSet::new(), - used_crates: HashSet::new(), emit_errors: true, make_glob_map: make_glob_map == MakeGlobMap::Yes, glob_map: NodeMap(), + used_imports: HashSet::new(), + used_crates: HashSet::new(), + maybe_unused_trait_imports: NodeSet(), + callback: None, resolved: false, privacy_errors: Vec::new(), @@ -1232,7 +1233,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } #[inline] - fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) { + fn record_use(&mut self, name: Name, binding: &'a NameBinding<'a>) { // track extern crates for unused_extern_crate lint if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) { self.used_crates.insert(krate); @@ -1244,7 +1245,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { _ => return, }; - self.used_imports.insert((directive.id, ns)); if let Some(error) = privacy_error.as_ref() { self.privacy_errors.push((**error).clone()); } @@ -1555,7 +1555,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { false => module.resolve_name(name, namespace, false), }.and_then(|binding| { if record_used { - self.record_use(name, namespace, binding); + if let NameBindingKind::Import { directive, .. } = binding.kind { + self.used_imports.insert((directive.id, namespace)); + } + self.record_use(name, binding); } Success(binding) }) @@ -3217,21 +3220,27 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn get_traits_containing_item(&mut self, name: Name) -> Vec { + fn get_traits_containing_item(&mut self, name: Name) -> Vec { debug!("(getting traits containing item) looking for '{}'", name); - fn add_trait_info(found_traits: &mut Vec, trait_def_id: DefId, name: Name) { + fn add_trait_info(found_traits: &mut Vec, + trait_def_id: DefId, + import_id: Option, + name: Name) { debug!("(adding trait info) found trait {:?} for method '{}'", trait_def_id, name); - found_traits.push(trait_def_id); + found_traits.push(TraitCandidate { + def_id: trait_def_id, + import_id: import_id, + }); } let mut found_traits = Vec::new(); // Look for the current trait. if let Some((trait_def_id, _)) = self.current_trait_ref { if self.trait_item_map.contains_key(&(name, trait_def_id)) { - add_trait_info(&mut found_traits, trait_def_id, name); + add_trait_info(&mut found_traits, trait_def_id, None, name); } } @@ -3254,9 +3263,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { for binding in traits.as_ref().unwrap().iter() { let trait_def_id = binding.def().unwrap().def_id(); if self.trait_item_map.contains_key(&(name, trait_def_id)) { - add_trait_info(&mut found_traits, trait_def_id, name); + let mut import_id = None; + if let NameBindingKind::Import { directive, .. } = binding.kind { + let id = directive.id; + self.maybe_unused_trait_imports.insert(id); + import_id = Some(id); + } + add_trait_info(&mut found_traits, trait_def_id, import_id, name); let trait_name = self.get_trait_name(trait_def_id); - self.record_use(trait_name, TypeNS, binding); + self.record_use(trait_name, binding); } } }; @@ -3636,6 +3651,7 @@ fn err_path_resolution() -> PathResolution { pub struct CrateMap { pub def_map: RefCell, pub freevars: FreevarMap, + pub maybe_unused_trait_imports: NodeSet, pub export_map: ExportMap, pub trait_map: TraitMap, pub glob_map: Option, @@ -3673,6 +3689,7 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session, CrateMap { def_map: resolver.def_map, freevars: resolver.freevars, + maybe_unused_trait_imports: resolver.maybe_unused_trait_imports, export_map: resolver.export_map, trait_map: resolver.trait_map, glob_map: if resolver.make_glob_map { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index f335f145a1072..07a77e45c6c74 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -25,7 +25,6 @@ use rustc::lint; use rustc::hir::def::*; use syntax::ast::{NodeId, Name}; -use syntax::attr::AttrMetaMethods; use syntax::codemap::Span; use syntax::util::lev_distance::find_best_match_for_name; diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index 7f2f2618c3c96..3a9507b5d6e4c 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -13,8 +13,6 @@ //! The `Dump` trait can be used together with `DumpVisitor` in order to //! retrieve the data from a crate. -use std::hash::Hasher; - use rustc::hir::def_id::DefId; use rustc::ty; use syntax::ast::{CrateNum, NodeId}; diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index 514fc52d0085b..aea61da18a0a1 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -21,8 +21,6 @@ use std::process::{Command, Output, Stdio}; use std::ptr; use std::str; -use middle::cstore::CrateStore; - use libc; use llvm::archive_ro::{ArchiveRO, Child}; use llvm::{self, ArchiveKind}; diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 4e77b2bc06940..3e69bb204b92d 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -19,7 +19,7 @@ use session::config::{OutputFilenames, Input, OutputType}; use session::filesearch; use session::search_paths::PathKind; use session::Session; -use middle::cstore::{self, CrateStore, LinkMeta}; +use middle::cstore::{self, LinkMeta}; use middle::cstore::{LinkagePreference, NativeLibraryKind}; use middle::dependency_format::Linkage; use CrateTranslation; diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index c02a482f81275..8055e97034e3f 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -16,7 +16,6 @@ use std::path::{Path, PathBuf}; use std::process::Command; use back::archive; -use middle::cstore::CrateStore; use middle::dependency_format::Linkage; use session::Session; use session::config::CrateTypeDylib; diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index cea67f46db527..08fce902120d2 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -35,7 +35,6 @@ use lint; use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; use rustc::cfg; -use middle::cstore::CrateStore; use rustc::hir::def_id::DefId; use rustc::infer; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 5ce7caf5deb06..70348cf35e5f5 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -39,7 +39,7 @@ use type_::Type; use value::Value; use rustc::ty::{self, Ty, TyCtxt}; use rustc::traits::{self, SelectionContext, ProjectionMode}; -use rustc::ty::fold::{TypeFolder, TypeFoldable}; +use rustc::ty::fold::TypeFoldable; use rustc::hir; use util::nodemap::NodeMap; diff --git a/src/librustc_trans/inline.rs b/src/librustc_trans/inline.rs index 1eff09d67f96b..af175fbf88256 100644 --- a/src/librustc_trans/inline.rs +++ b/src/librustc_trans/inline.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::{AvailableExternallyLinkage, InternalLinkage, SetLinkage}; -use middle::cstore::{CrateStore, FoundAst, InlinedItem}; +use middle::cstore::{FoundAst, InlinedItem}; use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; use base::{push_ctxt, trans_item, trans_fn}; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 674c3d6f9a17a..ffbd334557e9b 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -155,6 +155,12 @@ pub trait AstConv<'tcx> { _trait_ref: ty::TraitRef<'tcx>, _item_name: ast::Name) -> Ty<'tcx>; + + /// Invoked when we encounter an error from some prior pass + /// (e.g. resolve) that is translated into a ty-error. This is + /// used to help suppress derived errors typeck might otherwise + /// report. + fn set_tainted_by_errors(&self); } pub fn ast_region_to_region(tcx: &TyCtxt, lifetime: &hir::Lifetime) @@ -1533,6 +1539,7 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, prim_ty_to_ty(tcx, base_segments, prim_ty) } Def::Err => { + this.set_tainted_by_errors(); return this.tcx().types.err; } _ => { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 8dbd6496b6fb0..a7a04f4a85fe8 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -209,6 +209,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let self_ty = fcx.to_ty(&qself.ty); let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) { if d.base_def == Def::Err { + fcx.infcx().set_tainted_by_errors(); fcx.write_error(pat.id); return; } @@ -628,6 +629,7 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let path_res = match tcx.def_map.borrow().get(&pat.id) { Some(&path_res) if path_res.base_def != Def::Err => path_res, _ => { + fcx.infcx().set_tainted_by_errors(); fcx.write_error(pat.id); if let Some(subpats) = subpats { diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 91cdb8d966d41..922c411ce8cd8 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -45,12 +45,13 @@ use super::structurally_resolved_type; use lint; use hir::def_id::DefId; +use rustc::hir; +use rustc::traits; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::cast::{CastKind, CastTy}; -use syntax::codemap::Span; -use rustc::hir; use syntax::ast; - +use syntax::codemap::Span; +use util::common::ErrorReported; /// Reifies a cast check to be checked once we have full type information for /// a function context. @@ -58,6 +59,7 @@ pub struct CastCheck<'tcx> { expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, + cast_span: Span, span: Span, } @@ -111,17 +113,37 @@ enum CastError { } impl<'tcx> CastCheck<'tcx> { - pub fn new(expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span) - -> CastCheck<'tcx> { - CastCheck { + pub fn new<'a>(fcx: &FnCtxt<'a, 'tcx>, + expr: &'tcx hir::Expr, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, + cast_span: Span, + span: Span) + -> Result, ErrorReported> { + let check = CastCheck { expr: expr, expr_ty: expr_ty, cast_ty: cast_ty, + cast_span: cast_span, span: span, + }; + + // For better error messages, check for some obviously unsized + // cases now. We do a more thorough check at the end, once + // inference is more completely known. + match cast_ty.sty { + ty::TyTrait(..) | ty::TySlice(..) => { + check.report_cast_to_unsized_type(fcx); + Err(ErrorReported) + } + _ => { + Ok(check) + } } } - fn report_cast_error<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, + fn report_cast_error<'a>(&self, + fcx: &FnCtxt<'a, 'tcx>, e: CastError) { match e { CastError::NeedViaPtr | @@ -186,6 +208,61 @@ impl<'tcx> CastCheck<'tcx> { } } + fn report_cast_to_unsized_type<'a>(&self, + fcx: &FnCtxt<'a, 'tcx>) { + if + self.cast_ty.references_error() || + self.expr_ty.references_error() + { + return; + } + + let tstr = fcx.infcx().ty_to_string(self.cast_ty); + let mut err = fcx.type_error_struct(self.span, |actual| { + format!("cast to unsized type: `{}` as `{}`", actual, tstr) + }, self.expr_ty, None); + match self.expr_ty.sty { + ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => { + let mtstr = match mt { + hir::MutMutable => "mut ", + hir::MutImmutable => "" + }; + if self.cast_ty.is_trait() { + match fcx.tcx().sess.codemap().span_to_snippet(self.cast_span) { + Ok(s) => { + err.span_suggestion(self.cast_span, + "try casting to a reference instead:", + format!("&{}{}", mtstr, s)); + }, + Err(_) => + span_help!(err, self.cast_span, + "did you mean `&{}{}`?", mtstr, tstr), + } + } else { + span_help!(err, self.span, + "consider using an implicit coercion to `&{}{}` instead", + mtstr, tstr); + } + } + ty::TyBox(..) => { + match fcx.tcx().sess.codemap().span_to_snippet(self.cast_span) { + Ok(s) => { + err.span_suggestion(self.cast_span, + "try casting to a `Box` instead:", + format!("Box<{}>", s)); + }, + Err(_) => + span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr), + } + } + _ => { + span_help!(err, self.expr.span, + "consider using a box or reference as appropriate"); + } + } + err.emit(); + } + fn trivial_cast_lint<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { let t_cast = self.cast_ty; let t_expr = self.expr_ty; @@ -218,7 +295,9 @@ impl<'tcx> CastCheck<'tcx> { debug!("check_cast({}, {:?} as {:?})", self.expr.id, self.expr_ty, self.cast_ty); - if self.expr_ty.references_error() || self.cast_ty.references_error() { + if !fcx.type_is_known_to_be_sized(self.cast_ty, self.span) { + self.report_cast_to_unsized_type(fcx); + } else if self.expr_ty.references_error() || self.cast_ty.references_error() { // No sense in giving duplicate error messages } else if self.try_coercion_cast(fcx) { self.trivial_cast_lint(fcx); @@ -403,3 +482,17 @@ impl<'tcx> CastCheck<'tcx> { } } + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + fn type_is_known_to_be_sized(&self, + ty: Ty<'tcx>, + span: Span) + -> bool + { + traits::type_known_to_meet_builtin_bound(self.infcx(), + ty, + ty::BoundSized, + span) + } +} + diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index f1c6868efd210..711d695a6ef1d 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -71,7 +71,7 @@ use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty, TyCtxt}; use rustc::ty::fold::TypeFoldable; use rustc::ty::error::TypeError; -use rustc::ty::relate::{RelateResult, TypeRelation}; +use rustc::ty::relate::RelateResult; use util::common::indent; use std::cell::RefCell; diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index eae0cfb0f2267..638960beaa05e 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -11,18 +11,15 @@ //! Type-checking for the rust-intrinsic and platform-intrinsic //! intrinsics that the compiler exposes. -use astconv::AstConv; use intrinsics; use rustc::ty::subst::{self, Substs}; use rustc::ty::FnSig; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::fold::TypeFolder; use {CrateCtxt, require_same_types}; use std::collections::{HashMap}; use syntax::abi::Abi; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax::codemap::Span; use syntax::parse::token; diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 31d95af4fbb9c..26d1f50f8c549 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -10,7 +10,6 @@ //! Method lookup: the secret sauce of Rust. See `README.md`. -use astconv::AstConv; use check::FnCtxt; use hir::def::Def; use hir::def_id::DefId; @@ -129,6 +128,11 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let mode = probe::Mode::MethodCall; let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty); let pick = probe::probe(fcx, span, mode, method_name, self_ty, call_expr.id)?; + + if let Some(import_id) = pick.import_id { + fcx.tcx().used_trait_imports.borrow_mut().insert(import_id); + } + Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types)) } @@ -340,8 +344,12 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, { let mode = probe::Mode::Path; let pick = probe::probe(fcx, span, mode, method_name, self_ty, expr_id)?; - let def = pick.item.def(); + if let Some(import_id) = pick.import_id { + fcx.tcx().used_trait_imports.borrow_mut().insert(import_id); + } + + let def = pick.item.def(); if let probe::InherentImplPick = pick.kind { if !pick.item.vis().is_accessible_from(fcx.body_id, &fcx.tcx().map) { let msg = format!("{} `{}` is private", def.kind_name(), &method_name.as_str()); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 2defbf0d33e0a..4716bab71bfb1 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -42,6 +42,7 @@ struct ProbeContext<'a, 'tcx:'a> { inherent_candidates: Vec>, extension_candidates: Vec>, impl_dups: HashSet, + import_id: Option, /// Collects near misses when the candidate functions are missing a `self` keyword and is only /// used for error reporting @@ -67,6 +68,7 @@ struct Candidate<'tcx> { xform_self_ty: Ty<'tcx>, item: ty::ImplOrTraitItem<'tcx>, kind: CandidateKind<'tcx>, + import_id: Option, } #[derive(Debug)] @@ -84,6 +86,7 @@ enum CandidateKind<'tcx> { pub struct Pick<'tcx> { pub item: ty::ImplOrTraitItem<'tcx>, pub kind: PickKind<'tcx>, + pub import_id: Option, // Indicates that the source expression should be autoderef'd N times // @@ -247,6 +250,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { inherent_candidates: Vec::new(), extension_candidates: Vec::new(), impl_dups: HashSet::new(), + import_id: None, steps: Rc::new(steps), opt_simplified_steps: opt_simplified_steps, static_candidates: Vec::new(), @@ -435,7 +439,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item, - kind: InherentImplCandidate(impl_substs, obligations) + kind: InherentImplCandidate(impl_substs, obligations), + import_id: self.import_id, }); } @@ -463,7 +468,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item, - kind: ObjectCandidate + kind: ObjectCandidate, + import_id: this.import_id, }); }); } @@ -533,7 +539,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item, - kind: WhereClauseCandidate(poly_trait_ref) + kind: WhereClauseCandidate(poly_trait_ref), + import_id: this.import_id, }); }); } @@ -577,9 +584,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let mut duplicates = HashSet::new(); let opt_applicable_traits = self.fcx.ccx.trait_map.get(&expr_id); if let Some(applicable_traits) = opt_applicable_traits { - for &trait_did in applicable_traits { + for trait_candidate in applicable_traits { + let trait_did = trait_candidate.def_id; if duplicates.insert(trait_did) { - self.assemble_extension_candidates_for_trait(trait_did)?; + self.import_id = trait_candidate.import_id; + let result = self.assemble_extension_candidates_for_trait(trait_did); + self.import_id = None; + result?; } } } @@ -679,7 +690,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.extension_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: ExtensionImplCandidate(impl_def_id, impl_substs, obligations) + kind: ExtensionImplCandidate(impl_def_id, impl_substs, obligations), + import_id: self.import_id, }); }); } @@ -754,7 +766,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: TraitCandidate + kind: TraitCandidate, + import_id: self.import_id, }); } @@ -811,7 +824,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.extension_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: TraitCandidate + kind: TraitCandidate, + import_id: self.import_id, }); } } @@ -842,7 +856,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.extension_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: WhereClauseCandidate(poly_bound) + kind: WhereClauseCandidate(poly_bound), + import_id: self.import_id, }); } } @@ -1140,6 +1155,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { Some(Pick { item: probes[0].item.clone(), kind: TraitPick, + import_id: probes[0].import_id, autoderefs: 0, autoref: None, unsize: None @@ -1345,6 +1361,7 @@ impl<'tcx> Candidate<'tcx> { WhereClausePick(trait_ref.clone()) } }, + import_id: self.import_id, autoderefs: 0, autoref: None, unsize: None diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index c5195cf8787da..e1a7170c04e9b 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -13,11 +13,10 @@ use CrateCtxt; -use astconv::AstConv; use check::{self, FnCtxt, UnresolvedTypeAction, autoderef}; use rustc::hir::map as hir_map; use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable}; -use middle::cstore::{self, CrateStore}; +use middle::cstore; use hir::def::Def; use hir::def_id::DefId; use middle::lang_items::FnOnceTraitLangItem; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 67b91f7838c66..3b1792050c46d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -99,8 +99,7 @@ use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility}; use rustc::ty::{MethodCall, MethodCallee}; use rustc::ty::adjustment; use rustc::ty::error::TypeError; -use rustc::ty::fold::{TypeFolder, TypeFoldable}; -use rustc::ty::relate::TypeRelation; +use rustc::ty::fold::TypeFoldable; use rustc::ty::util::{Representability, IntTypeExt}; use require_c_abi_if_variadic; use rscope::{ElisionFailureInfo, RegionScope}; @@ -1076,64 +1075,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - t_span: Span, - e_span: Span, - t_cast: Ty<'tcx>, - t_expr: Ty<'tcx>, - id: ast::NodeId) { - if t_cast.references_error() || t_expr.references_error() { - return; - } - let tstr = fcx.infcx().ty_to_string(t_cast); - let mut err = fcx.type_error_struct(span, |actual| { - format!("cast to unsized type: `{}` as `{}`", actual, tstr) - }, t_expr, None); - match t_expr.sty { - ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => { - let mtstr = match mt { - hir::MutMutable => "mut ", - hir::MutImmutable => "" - }; - if t_cast.is_trait() { - match fcx.tcx().sess.codemap().span_to_snippet(t_span) { - Ok(s) => { - err.span_suggestion(t_span, - "try casting to a reference instead:", - format!("&{}{}", mtstr, s)); - }, - Err(_) => - span_help!(err, t_span, - "did you mean `&{}{}`?", mtstr, tstr), - } - } else { - span_help!(err, span, - "consider using an implicit coercion to `&{}{}` instead", - mtstr, tstr); - } - } - ty::TyBox(..) => { - match fcx.tcx().sess.codemap().span_to_snippet(t_span) { - Ok(s) => { - err.span_suggestion(t_span, - "try casting to a `Box` instead:", - format!("Box<{}>", s)); - }, - Err(_) => - span_help!(err, t_span, "did you mean `Box<{}>`?", tstr), - } - } - _ => { - span_help!(err, e_span, - "consider using a box or reference as appropriate"); - } - } - err.emit(); - fcx.write_error(id); -} - - impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { fn tcx(&self) -> &TyCtxt<'tcx> { self.ccx.tcx } @@ -1240,6 +1181,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { { self.normalize_associated_type(span, trait_ref, item_name) } + + fn set_tainted_by_errors(&self) { + self.infcx().set_tainted_by_errors() + } } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -1524,17 +1469,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized(self.expr_ty(expr), expr.span, code); } - pub fn type_is_known_to_be_sized(&self, - ty: Ty<'tcx>, - span: Span) - -> bool - { - traits::type_known_to_meet_builtin_bound(self.infcx(), - ty, - ty::BoundSized, - span) - } - pub fn register_builtin_bound(&self, ty: Ty<'tcx>, builtin_bound: ty::BuiltinBound, @@ -1771,16 +1705,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn default_type_parameters(&self) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; + + // Defaulting inference variables becomes very dubious if we have + // encountered type-checking errors. Therefore, if we think we saw + // some errors in this function, just resolve all uninstanted type + // varibles to TyError. + if self.infcx().is_tainted_by_errors() { + for ty in &self.infcx().unsolved_variables() { + if let ty::TyInfer(_) = self.infcx().shallow_resolve(ty).sty { + debug!("default_type_parameters: defaulting `{:?}` to error", ty); + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.err); + } + } + return; + } + for ty in &self.infcx().unsolved_variables() { let resolved = self.infcx().resolve_type_vars_if_possible(ty); if self.infcx().type_var_diverges(resolved) { + debug!("default_type_parameters: defaulting `{:?}` to `()` because it diverges", + resolved); demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); } else { match self.infcx().type_is_unconstrained_numeric(resolved) { UnconstrainedInt => { + debug!("default_type_parameters: defaulting `{:?}` to `i32`", + resolved); demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) }, UnconstrainedFloat => { + debug!("default_type_parameters: defaulting `{:?}` to `f32`", + resolved); demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) } Neither => { } @@ -3232,6 +3187,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Find the relevant variant let def = lookup_full_def(tcx, path.span, expr.id); if def == Def::Err { + fcx.infcx().set_tainted_by_errors(); check_struct_fields_on_error(fcx, expr.id, fields, base_expr); return; } @@ -3435,6 +3391,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr.span, id); } else { + fcx.infcx().set_tainted_by_errors(); fcx.write_ty(id, fcx.tcx().types.err); } } @@ -3560,7 +3517,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Find the type of `e`. Supply hints based on the type we are casting to, // if appropriate. let t_cast = fcx.to_ty(t); - let t_cast = structurally_resolved_type(fcx, expr.span, t_cast); + let t_cast = fcx.infcx().resolve_type_vars_if_possible(&t_cast); check_expr_with_expectation(fcx, e, ExpectCastableToType(t_cast)); let t_expr = fcx.expr_ty(e); let t_cast = fcx.infcx().resolve_type_vars_if_possible(&t_cast); @@ -3568,8 +3525,6 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Eagerly check for some obvious errors. if t_expr.references_error() || t_cast.references_error() { fcx.write_error(id); - } else if !fcx.type_is_known_to_be_sized(t_cast, expr.span) { - report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_cast, t_expr, id); } else { // Write a type for the whole expression, assuming everything is going // to work out Ok. @@ -3577,8 +3532,14 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Defer other checks until we're done type checking. let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut(); - let cast_check = cast::CastCheck::new(e, t_expr, t_cast, expr.span); - deferred_cast_checks.push(cast_check); + match cast::CastCheck::new(fcx, e, t_expr, t_cast, t.span, expr.span) { + Ok(cast_check) => { + deferred_cast_checks.push(cast_check); + } + Err(ErrorReported) => { + fcx.write_error(id); + } + } } } hir::ExprType(ref e, ref t) => { @@ -4408,8 +4369,12 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Def::ForeignMod(..) | Def::Local(..) | Def::Label(..) | - Def::Upvar(..) | + Def::Upvar(..) => { + segment_spaces = vec![None; segments.len()]; + } + Def::Err => { + fcx.infcx().set_tainted_by_errors(); segment_spaces = vec![None; segments.len()]; } } @@ -4769,9 +4734,11 @@ fn structurally_resolve_type_or_else<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // If not, error. if alternative.is_ty_var() || alternative.references_error() { - fcx.type_error_message(sp, |_actual| { - "the type of this value must be known in this context".to_string() - }, ty, None); + if !fcx.infcx().is_tainted_by_errors() { + fcx.type_error_message(sp, |_actual| { + "the type of this value must be known in this context".to_string() + }, ty, None); + } demand::suptype(fcx, sp, fcx.tcx().types.err, ty); ty = fcx.tcx().types.err; } else { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 2a4de6e091b3d..ffcfe2752e333 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -82,7 +82,6 @@ //! relation, except that a borrowed pointer never owns its //! contents. -use astconv::AstConv; use check::dropck; use check::FnCtxt; use middle::free_region::FreeRegionMap; diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 1b21e6ce9ebe3..587946124b29d 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use astconv::AstConv; use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck}; use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; @@ -17,7 +16,6 @@ use middle::region::{CodeExtent}; use rustc::ty::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::fold::{TypeFolder}; use std::cell::RefCell; use std::collections::HashSet; diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 68327ccd39ab6..d62bb3e11791f 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -13,7 +13,6 @@ // substitutions. use self::ResolveReason::*; -use astconv::AstConv; use check::FnCtxt; use hir::def_id::DefId; use hir::pat_util; diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs new file mode 100644 index 0000000000000..3c594ebdf0bfc --- /dev/null +++ b/src/librustc_typeck/check_unused.rs @@ -0,0 +1,64 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use lint; +use rustc::dep_graph::DepNode; +use rustc::ty::TyCtxt; + +use syntax::ast; +use syntax::codemap::{Span, DUMMY_SP}; + +use rustc::hir; +use rustc::hir::intravisit::Visitor; + +struct UnusedTraitImportVisitor<'a, 'tcx: 'a> { + tcx: &'a TyCtxt<'tcx>, +} + +impl<'a, 'tcx> UnusedTraitImportVisitor<'a, 'tcx> { + fn check_import(&self, id: ast::NodeId, span: Span) { + if !self.tcx.maybe_unused_trait_imports.contains(&id) { + return; + } + if self.tcx.used_trait_imports.borrow().contains(&id) { + return; + } + self.tcx.sess.add_lint(lint::builtin::UNUSED_IMPORTS, + id, + span, + "unused import".to_string()); + } +} + +impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> { + fn visit_item(&mut self, item: &hir::Item) { + if item.vis == hir::Public || item.span == DUMMY_SP { + return; + } + if let hir::ItemUse(ref path) = item.node { + match path.node { + hir::ViewPathSimple(..) | hir::ViewPathGlob(..) => { + self.check_import(item.id, path.span); + } + hir::ViewPathList(_, ref path_list) => { + for path_item in path_list { + self.check_import(path_item.node.id(), path_item.span); + } + } + } + } + } +} + +pub fn check_crate(tcx: &TyCtxt) { + let _task = tcx.dep_graph.in_task(DepNode::UnusedTraitCheck); + let mut visitor = UnusedTraitImportVisitor { tcx: tcx }; + tcx.map.krate().visit_all_items(&mut visitor); +} diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index a05167dbe4333..30d181abb9e9d 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -12,7 +12,6 @@ //! same type. Likewise, no two inherent impls for a given type //! constructor provide a method with the same name. -use middle::cstore::CrateStore; use hir::def_id::DefId; use rustc::traits::{self, ProjectionMode}; use rustc::infer; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6d95586bed019..e6dd6ad02174d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -74,7 +74,6 @@ use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPer use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; use rustc::ty::{VariantKind}; -use rustc::ty::fold::{TypeFolder}; use rustc::ty::util::IntTypeExt; use rscope::*; use rustc::dep_graph::DepNode; @@ -384,6 +383,10 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { { self.tcx().mk_projection(trait_ref, item_name) } + + fn set_tainted_by_errors(&self) { + // no obvious place to track this, just let it go + } } /// Interface used to find the bounds on a type parameter from within diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 7f27d10ce1ec3..a2ab81b4f7f4d 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -122,6 +122,7 @@ use std::cell::RefCell; pub mod diagnostics; pub mod check; +pub mod check_unused; mod rscope; mod astconv; pub mod collect; @@ -361,6 +362,7 @@ pub fn check_crate(tcx: &TyCtxt, trait_map: hir::TraitMap) -> CompileResult { time(time_passes, "drop-impl checking", || check::check_drop_impls(&ccx))?; + check_unused::check_crate(tcx); check_for_entry_fn(&ccx); let err_count = tcx.sess.err_count(); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index fd57a452e0aba..b1c478cacffb1 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -14,10 +14,9 @@ use std::collections::HashSet; use std::iter::once; use syntax::ast; -use syntax::attr::AttrMetaMethods; use rustc::hir; -use rustc::middle::cstore::{self, CrateStore}; +use rustc::middle::cstore; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::ty::{self, TyCtxt}; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c9f40a1adae32..c49e52bcb7e56 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -35,7 +35,7 @@ use syntax::parse::token::{self, InternedString, special_idents}; use syntax::ptr::P; use rustc_trans::back::link; -use rustc::middle::cstore::{self, CrateStore}; +use rustc::middle::cstore; use rustc::middle::privacy::AccessLevels; use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex}; diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 8b2e84974985c..a168fe98a94cf 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -9,7 +9,6 @@ // except according to those terms. use std::fmt; -use std::io::prelude::*; use std::io; use externalfiles::ExternalHtml; diff --git a/src/libstd/collections/hash/bench.rs b/src/libstd/collections/hash/bench.rs index 9fae9af2d54d4..a1275d23d5710 100644 --- a/src/libstd/collections/hash/bench.rs +++ b/src/libstd/collections/hash/bench.rs @@ -11,7 +11,6 @@ #![cfg(test)] extern crate test; -use prelude::v1::*; use self::test::Bencher; diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 9a605fc7bbff4..e142c78569bd7 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -350,7 +350,6 @@ mod test { use prelude::v1::*; use super::{Error, ErrorKind}; use error; - use error::Error as error_Error; use fmt; use sys::os::error_string; diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index f771ee95bd121..35aa827782ddf 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -1394,6 +1394,56 @@ impl CodeMap { pub fn count_lines(&self) -> usize { self.files.borrow().iter().fold(0, |a, f| a + f.count_lines()) } + + pub fn macro_backtrace(&self, span: Span) -> Vec { + let mut last_span = DUMMY_SP; + let mut span = span; + let mut result = vec![]; + loop { + let span_name_span = self.with_expn_info(span.expn_id, |expn_info| { + expn_info.map(|ei| { + let (pre, post) = match ei.callee.format { + MacroAttribute(..) => ("#[", "]"), + MacroBang(..) => ("", "!"), + }; + let macro_decl_name = format!("{}{}{}", + pre, + ei.callee.name(), + post); + let def_site_span = ei.callee.span; + (ei.call_site, macro_decl_name, def_site_span) + }) + }); + + match span_name_span { + None => break, + Some((call_site, macro_decl_name, def_site_span)) => { + // Don't print recursive invocations + if !call_site.source_equal(&last_span) { + result.push(MacroBacktrace { + call_site: call_site, + macro_decl_name: macro_decl_name, + def_site_span: def_site_span, + }); + } + last_span = span; + span = call_site; + } + } + } + result + } +} + +pub struct MacroBacktrace { + /// span where macro was applied to generate this code + pub call_site: Span, + + /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]") + pub macro_decl_name: String, + + /// span where macro was defined (if known) + pub def_site_span: Option, } // _____________________________________________________________________________ diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 61fdc8453d8fd..0b5234769b219 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -577,46 +577,17 @@ impl EmitterWriter { fn print_macro_backtrace(&mut self, sp: Span) -> io::Result<()> { - let mut last_span = codemap::DUMMY_SP; - let mut span = sp; - - loop { - let span_name_span = self.cm.with_expn_info(span.expn_id, |expn_info| { - expn_info.map(|ei| { - let (pre, post) = match ei.callee.format { - codemap::MacroAttribute(..) => ("#[", "]"), - codemap::MacroBang(..) => ("", "!"), - }; - let macro_decl_name = format!("in this expansion of {}{}{}", - pre, - ei.callee.name(), - post); - let def_site_span = ei.callee.span; - (ei.call_site, macro_decl_name, def_site_span) - }) - }); - let (macro_decl_name, def_site_span) = match span_name_span { - None => break, - Some((sp, macro_decl_name, def_site_span)) => { - span = sp; - (macro_decl_name, def_site_span) - } - }; - - // Don't print recursive invocations - if !span.source_equal(&last_span) { - let mut diag_string = macro_decl_name; - if let Some(def_site_span) = def_site_span { - diag_string.push_str(&format!(" (defined in {})", - self.cm.span_to_filename(def_site_span))); - } - - let snippet = self.cm.span_to_string(span); - print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?; + for trace in self.cm.macro_backtrace(sp) { + let mut diag_string = + format!("in this expansion of {}", trace.macro_decl_name); + if let Some(def_site_span) = trace.def_site_span { + diag_string.push_str( + &format!(" (defined in {})", + self.cm.span_to_filename(def_site_span))); } - last_span = span; + let snippet = self.cm.span_to_string(sp); + print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?; } - Ok(()) } } diff --git a/src/libsyntax/errors/json.rs b/src/libsyntax/errors/json.rs index f369582bc5c30..821617bfe89df 100644 --- a/src/libsyntax/errors/json.rs +++ b/src/libsyntax/errors/json.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -20,13 +20,14 @@ // FIXME spec the JSON output properly. -use codemap::{self, Span, MultiSpan, CodeMap}; +use codemap::{self, Span, MacroBacktrace, MultiSpan, CodeMap}; use diagnostics::registry::Registry; use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion}; use errors::emitter::Emitter; use std::rc::Rc; use std::io::{self, Write}; +use std::vec; use rustc_serialize::json::as_json; @@ -84,8 +85,12 @@ struct Diagnostic<'a> { /// "error: internal compiler error", "error", "warning", "note", "help". level: &'static str, spans: Vec, - /// Assocaited diagnostic messages. + /// Associated diagnostic messages. children: Vec>, + /// The message as rustc would render it. Currently this is only + /// `Some` for "suggestions", but eventually it will include all + /// snippets. + rendered: Option, } #[derive(RustcEncodable)] @@ -101,16 +106,39 @@ struct DiagnosticSpan { column_end: usize, /// Source text from the start of line_start to the end of line_end. text: Vec, + /// If we are suggesting a replacement, this will contain text + /// that should be sliced in atop this span. You may prefer to + /// load the fully rendered version from the parent `Diagnostic`, + /// however. + suggested_replacement: Option, + /// Macro invocations that created the code at this span, if any. + expansion: Option>, } #[derive(RustcEncodable)] struct DiagnosticSpanLine { text: String, + /// 1-based, character offset in self.text. highlight_start: usize, + highlight_end: usize, } +#[derive(RustcEncodable)] +struct DiagnosticSpanMacroExpansion { + /// span where macro was applied to generate this code; note that + /// this may itself derive from a macro (if + /// `span.expansion.is_some()`) + span: DiagnosticSpan, + + /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]") + macro_decl_name: String, + + /// span where macro was defined (if known) + def_site_span: Option, +} + #[derive(RustcEncodable)] struct DiagnosticCode { /// The code itself. @@ -132,6 +160,7 @@ impl<'a> Diagnostic<'a> { level: level.to_str(), spans: msp.map_or(vec![], |msp| DiagnosticSpan::from_multispan(msp, je)), children: vec![], + rendered: None, } } @@ -146,6 +175,7 @@ impl<'a> Diagnostic<'a> { level: level.to_str(), spans: DiagnosticSpan::from_render_span(span, je), children: vec![], + rendered: je.render(span), } } @@ -160,6 +190,7 @@ impl<'a> Diagnostic<'a> { children: db.children.iter().map(|c| { Diagnostic::from_sub_diagnostic(c, je) }).collect(), + rendered: None, } } @@ -173,37 +204,91 @@ impl<'a> Diagnostic<'a> { .or_else(|| db.span.as_ref().map(|s| DiagnosticSpan::from_multispan(s, je))) .unwrap_or(vec![]), children: vec![], + rendered: db.render_span.as_ref() + .and_then(|rsp| je.render(rsp)), } } } impl DiagnosticSpan { + fn from_span(span: Span, suggestion: Option<&String>, je: &JsonEmitter) + -> DiagnosticSpan { + // obtain the full backtrace from the `macro_backtrace` + // helper; in some ways, it'd be better to expand the + // backtrace ourselves, but the `macro_backtrace` helper makes + // some decision, such as dropping some frames, and I don't + // want to duplicate that logic here. + let backtrace = je.cm.macro_backtrace(span).into_iter(); + DiagnosticSpan::from_span_and_backtrace(span, suggestion, backtrace, je) + } + + fn from_span_and_backtrace(span: Span, + suggestion: Option<&String>, + mut backtrace: vec::IntoIter, + je: &JsonEmitter) + -> DiagnosticSpan { + let start = je.cm.lookup_char_pos(span.lo); + let end = je.cm.lookup_char_pos(span.hi); + let backtrace_step = + backtrace.next() + .map(|bt| { + let call_site = + Self::from_span_and_backtrace(bt.call_site, + None, + backtrace, + je); + let def_site_span = bt.def_site_span.map(|sp| { + Self::from_span_and_backtrace(sp, + None, + vec![].into_iter(), + je) + }); + Box::new(DiagnosticSpanMacroExpansion { + span: call_site, + macro_decl_name: bt.macro_decl_name, + def_site_span: def_site_span, + }) + }); + DiagnosticSpan { + file_name: start.file.name.clone(), + byte_start: span.lo.0, + byte_end: span.hi.0, + line_start: start.line, + line_end: end.line, + column_start: start.col.0 + 1, + column_end: end.col.0 + 1, + text: DiagnosticSpanLine::from_span(span, je), + suggested_replacement: suggestion.cloned(), + expansion: backtrace_step, + } + } + fn from_multispan(msp: &MultiSpan, je: &JsonEmitter) -> Vec { - msp.spans.iter().map(|span| { - let start = je.cm.lookup_char_pos(span.lo); - let end = je.cm.lookup_char_pos(span.hi); - DiagnosticSpan { - file_name: start.file.name.clone(), - byte_start: span.lo.0, - byte_end: span.hi.0, - line_start: start.line, - line_end: end.line, - column_start: start.col.0 + 1, - column_end: end.col.0 + 1, - text: DiagnosticSpanLine::from_span(span, je), - } - }).collect() + msp.spans.iter().map(|&span| Self::from_span(span, None, je)).collect() + } + + fn from_suggestion(suggestion: &CodeSuggestion, je: &JsonEmitter) + -> Vec { + assert_eq!(suggestion.msp.spans.len(), suggestion.substitutes.len()); + suggestion.msp.spans.iter() + .zip(&suggestion.substitutes) + .map(|(&span, suggestion)| { + DiagnosticSpan::from_span(span, Some(suggestion), je) + }) + .collect() } fn from_render_span(rsp: &RenderSpan, je: &JsonEmitter) -> Vec { match *rsp { - RenderSpan::FullSpan(ref msp) | - // FIXME(#30701) handle Suggestion properly - RenderSpan::Suggestion(CodeSuggestion { ref msp, .. }) => { + RenderSpan::FileLine(ref msp) | + RenderSpan::FullSpan(ref msp) => { DiagnosticSpan::from_multispan(msp, je) } + RenderSpan::Suggestion(ref suggestion) => { + DiagnosticSpan::from_suggestion(suggestion, je) + } RenderSpan::EndSpan(ref msp) => { - msp.spans.iter().map(|span| { + msp.spans.iter().map(|&span| { let end = je.cm.lookup_char_pos(span.hi); DiagnosticSpan { file_name: end.file.name.clone(), @@ -214,37 +299,11 @@ impl DiagnosticSpan { column_start: end.col.0 + 1, column_end: end.col.0 + 1, text: DiagnosticSpanLine::from_span_end(span, je), + suggested_replacement: None, + expansion: None, } }).collect() } - RenderSpan::FileLine(ref msp) => { - msp.spans.iter().map(|span| { - let start = je.cm.lookup_char_pos(span.lo); - let end = je.cm.lookup_char_pos(span.hi); - DiagnosticSpan { - file_name: start.file.name.clone(), - byte_start: span.lo.0, - byte_end: span.hi.0, - line_start: start.line, - line_end: end.line, - column_start: 0, - column_end: 0, - text: DiagnosticSpanLine::from_span(span, je), - } - }).collect() - } - } - } -} - -macro_rules! get_lines_for_span { - ($span: ident, $je: ident) => { - match $je.cm.span_to_lines(*$span) { - Ok(lines) => lines, - Err(_) => { - debug!("unprintable span"); - return Vec::new(); - } } } } @@ -265,45 +324,49 @@ impl DiagnosticSpanLine { /// Create a list of DiagnosticSpanLines from span - each line with any part /// of `span` gets a DiagnosticSpanLine, with the highlight indicating the /// `span` within the line. - fn from_span(span: &Span, je: &JsonEmitter) -> Vec { - let lines = get_lines_for_span!(span, je); - - let mut result = Vec::new(); - let fm = &*lines.file; - - for line in &lines.lines { - result.push(DiagnosticSpanLine::line_from_filemap(fm, - line.line_index, - line.start_col.0 + 1, - line.end_col.0 + 1)); - } - - result + fn from_span(span: Span, je: &JsonEmitter) -> Vec { + je.cm.span_to_lines(span) + .map(|lines| { + let fm = &*lines.file; + lines.lines + .iter() + .map(|line| { + DiagnosticSpanLine::line_from_filemap(fm, + line.line_index, + line.start_col.0 + 1, + line.end_col.0 + 1) + }) + .collect() + }) + .unwrap_or(vec![]) } /// Create a list of DiagnosticSpanLines from span - the result covers all /// of `span`, but the highlight is zero-length and at the end of `span`. - fn from_span_end(span: &Span, je: &JsonEmitter) -> Vec { - let lines = get_lines_for_span!(span, je); - - let mut result = Vec::new(); - let fm = &*lines.file; - - for (i, line) in lines.lines.iter().enumerate() { - // Invariant - CodeMap::span_to_lines will not return extra context - // lines - the last line returned is the last line of `span`. - let highlight = if i == lines.lines.len() - 1 { - (line.end_col.0 + 1, line.end_col.0 + 1) - } else { - (0, 0) - }; - result.push(DiagnosticSpanLine::line_from_filemap(fm, - line.line_index, - highlight.0, - highlight.1)); - } - - result + fn from_span_end(span: Span, je: &JsonEmitter) -> Vec { + je.cm.span_to_lines(span) + .map(|lines| { + let fm = &*lines.file; + lines.lines.iter() + .enumerate() + .map(|(i, line)| { + // Invariant - CodeMap::span_to_lines + // will not return extra context lines + // - the last line returned is the last + // line of `span`. + let highlight = if i == lines.lines.len() - 1 { + (line.end_col.0 + 1, line.end_col.0 + 1) + } else { + (0, 0) + }; + DiagnosticSpanLine::line_from_filemap(fm, + line.line_index, + highlight.0, + highlight.1) + }) + .collect() + }) + .unwrap_or(vec![]) } } @@ -322,3 +385,21 @@ impl DiagnosticCode { }) } } + +impl JsonEmitter { + fn render(&self, render_span: &RenderSpan) -> Option { + match *render_span { + RenderSpan::FileLine(_) | + RenderSpan::FullSpan(_) => { + None + } + RenderSpan::Suggestion(ref suggestion) => { + Some(suggestion.splice_lines(&self.cm)) + } + RenderSpan::EndSpan(_) => { + None + } + } + } +} + diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index a3420d75218fb..a3b0c885d6935 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -268,7 +268,6 @@ dependencies = [ "arena 0.0.0", "log 0.0.0", "rustc 0.0.0", - "rustc_bitflags 0.0.0", "syntax 0.0.0", ] diff --git a/src/test/compile-fail/associated-types-path-2.rs b/src/test/compile-fail/associated-types-path-2.rs index 0c077e37e43be..68fba56427cc5 100644 --- a/src/test/compile-fail/associated-types-path-2.rs +++ b/src/test/compile-fail/associated-types-path-2.rs @@ -28,8 +28,8 @@ pub fn f2(a: T) -> T::A { pub fn f1_int_int() { f1(2i32, 4i32); //~^ ERROR mismatched types - //~| expected u32 - //~| found i32 + //~| expected `u32` + //~| found `i32` } pub fn f1_int_uint() { diff --git a/src/test/compile-fail/block-must-not-have-result-do.rs b/src/test/compile-fail/block-must-not-have-result-do.rs index 30039a1c54c3a..2a6c71dbe3923 100644 --- a/src/test/compile-fail/block-must-not-have-result-do.rs +++ b/src/test/compile-fail/block-must-not-have-result-do.rs @@ -11,9 +11,5 @@ fn main() { loop { true //~ ERROR mismatched types - //~| expected () - //~| found bool - //~| expected () - //~| found bool } } diff --git a/src/test/compile-fail/block-must-not-have-result-res.rs b/src/test/compile-fail/block-must-not-have-result-res.rs index 6161660ddf7b3..8728685fc8b02 100644 --- a/src/test/compile-fail/block-must-not-have-result-res.rs +++ b/src/test/compile-fail/block-must-not-have-result-res.rs @@ -13,10 +13,6 @@ struct r; impl Drop for r { fn drop(&mut self) { true //~ ERROR mismatched types - //~| expected () - //~| found bool - //~| expected () - //~| found bool } } diff --git a/src/test/compile-fail/cast-as-bool.rs b/src/test/compile-fail/cast-as-bool.rs index 4764ae380ff44..af42d5c275c75 100644 --- a/src/test/compile-fail/cast-as-bool.rs +++ b/src/test/compile-fail/cast-as-bool.rs @@ -11,6 +11,5 @@ fn main() { let u = 5 as bool; //~^ ERROR cannot cast as `bool` - //~^^ HELP compare with zero instead - //~^^^ HELP run `rustc --explain E0054` to see a detailed explanation + //~| HELP compare with zero instead } diff --git a/src/test/parse-fail/keyword-priv-as-identifier.rs b/src/test/compile-fail/cast-rfc0401-2.rs similarity index 51% rename from src/test/parse-fail/keyword-priv-as-identifier.rs rename to src/test/compile-fail/cast-rfc0401-2.rs index e80feb66d6071..fdc250f994627 100644 --- a/src/test/parse-fail/keyword-priv-as-identifier.rs +++ b/src/test/compile-fail/cast-rfc0401-2.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,10 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only - -// This file was auto-generated using 'src/etc/generate-keyword-tests.py priv' +// RFC 401 test extracted into distinct file. This is because some the +// change to suppress "derived" errors wound up suppressing this error +// message, since the fallback for `3` doesn't occur. fn main() { - let priv = "foo"; //~ error: ident + let _ = 3 as bool; + //~^ ERROR cannot cast as `bool` + //~| HELP see a detailed explanation + //~| HELP compare with zero } diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index dcd49e34bb26c..05c531e91f128 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -58,14 +58,12 @@ fn main() let _ = f as *const u8; //~^ ERROR casting //~^^ HELP through a usize first - let _ = 3 as bool; + let _ = 3_i32 as bool; //~^ ERROR cannot cast as `bool` - //~^^ HELP compare with zero - //~^^^ HELP run `rustc --explain E0054` to see a detailed explanation + //~| HELP compare with zero let _ = E::A as bool; //~^ ERROR cannot cast as `bool` - //~^^ HELP compare with zero - //~^^^ HELP run `rustc --explain E0054` to see a detailed explanation + //~| HELP compare with zero let _ = 0x61u32 as char; //~ ERROR only `u8` can be cast let _ = false as f32; @@ -92,9 +90,8 @@ fn main() let _ = v as *const [u8]; //~ ERROR cannot cast let _ = fat_v as *const Foo; //~^ ERROR the trait bound `[u8]: std::marker::Sized` is not satisfied - //~^^ HELP run `rustc --explain E0277` to see a detailed explanation - //~^^^ NOTE `[u8]` does not have a constant size known at compile-time - //~^^^^ NOTE required for the cast to the object type `Foo` + //~| NOTE `[u8]` does not have a constant size known at compile-time + //~| NOTE required for the cast to the object type `Foo` let _ = foo as *const str; //~ ERROR casting let _ = foo as *mut str; //~ ERROR casting let _ = main as *mut str; //~ ERROR casting @@ -107,9 +104,8 @@ fn main() let a : *const str = "hello"; let _ = a as *const Foo; //~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied - //~^^ HELP run `rustc --explain E0277` to see a detailed explanation - //~^^^ NOTE `str` does not have a constant size known at compile-time - //~^^^^ NOTE required for the cast to the object type `Foo` + //~| NOTE `str` does not have a constant size known at compile-time + //~| NOTE required for the cast to the object type `Foo` // check no error cascade let _ = main.f as *const u32; //~ ERROR attempted access of field diff --git a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs index afc3b8d4ccddc..7fd1b17f2966c 100644 --- a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs +++ b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs @@ -20,7 +20,7 @@ impl !Send for TestType {} //~^ ERROR conflicting implementations of trait `std::marker::Send` unsafe impl Send for TestType {} -//~^ ERROR error: conflicting implementations of trait `std::marker::Send` +//~^ ERROR conflicting implementations of trait `std::marker::Send` impl !Send for TestType {} diff --git a/src/test/compile-fail/consider-removing-last-semi.rs b/src/test/compile-fail/consider-removing-last-semi.rs index 02148a138c9d9..2e110cb3d0bc8 100644 --- a/src/test/compile-fail/consider-removing-last-semi.rs +++ b/src/test/compile-fail/consider-removing-last-semi.rs @@ -9,13 +9,11 @@ // except according to those terms. fn f() -> String { //~ ERROR E0269 - //~^ HELP detailed explanation 0u8; "bla".to_string(); //~ HELP consider removing this semicolon } fn g() -> String { //~ ERROR E0269 - //~^ HELP detailed explanation "this won't work".to_string(); "removeme".to_string(); //~ HELP consider removing this semicolon } diff --git a/src/test/compile-fail/dep-graph-trait-impl-two-traits-same-method.rs b/src/test/compile-fail/dep-graph-trait-impl-two-traits-same-method.rs index 1afecd80ff5ad..5e4f43af669ca 100644 --- a/src/test/compile-fail/dep-graph-trait-impl-two-traits-same-method.rs +++ b/src/test/compile-fail/dep-graph-trait-impl-two-traits-same-method.rs @@ -15,6 +15,7 @@ #![feature(rustc_attrs)] #![allow(dead_code)] +#![allow(unused_imports)] fn main() { } diff --git a/src/test/compile-fail/issue-30580.rs b/src/test/compile-fail/derived-errors/issue-30580.rs similarity index 100% rename from src/test/compile-fail/issue-30580.rs rename to src/test/compile-fail/derived-errors/issue-30580.rs diff --git a/src/test/compile-fail/derived-errors/issue-31997-1.rs b/src/test/compile-fail/derived-errors/issue-31997-1.rs new file mode 100644 index 0000000000000..7d79c48c06ae2 --- /dev/null +++ b/src/test/compile-fail/derived-errors/issue-31997-1.rs @@ -0,0 +1,66 @@ +// Copyright 2012 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. + +// Regression test for this example from #31997 -- main goal is to +// emit as minimal and precise an error set as possible. Ideally, we'd +// only emit the E0433 error below, but right now we emit two. + +use std::io::prelude::*; +// use std::collections::HashMap; +use std::io; + +#[derive(Debug)] +struct Instance { + name: String, + start: Option, + end: Option, +} + +fn main() { + let input = io::stdin(); + let mut input = input.lock(); + + let mut map = HashMap::new(); + //~^ ERROR E0433 + + for line in input.lines() { + let line = line.unwrap(); + println!("process: {}", line); + let mut parts = line.splitn(2, ":"); + let _logfile = parts.next().unwrap(); + let rest = parts.next().unwrap(); + let mut parts = line.split(" [-] "); + + let stamp = parts.next().unwrap(); + + let rest = parts.next().unwrap(); + let words = rest.split_whitespace().collect::>(); + + let instance = words.iter().find(|a| a.starts_with("i-")).unwrap(); + let name = words[1].to_owned(); + let mut entry = map.entry(instance.to_owned()).or_insert(Instance { + name: name, + start: None, + end: None, + }); + + if rest.contains("terminating") { + assert!(entry.end.is_none()); + entry.end = Some(stamp.to_string()); + } + if rest.contains("waiting for") { + assert!(entry.start.is_none()); + entry.start = Some(stamp.to_string()); + } + + } + + println!("{:?}", map); +} diff --git a/src/test/compile-fail/derived-errors/issue-31997.rs b/src/test/compile-fail/derived-errors/issue-31997.rs new file mode 100644 index 0000000000000..cf283f6d3e4b5 --- /dev/null +++ b/src/test/compile-fail/derived-errors/issue-31997.rs @@ -0,0 +1,27 @@ +// Copyright 2012 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. + +// Test that the resolve failure does not lead to downstream type errors. +// See issue #31997. + +trait TheTrait { } + +fn closure(x: F) -> Result + where F: FnMut() -> T, T: TheTrait, +{ + unimplemented!() +} + +fn foo() -> Result<(), ()> { + try!(closure(|| bar(0 as *mut _))); //~ ERROR unresolved name `bar` + Ok(()) +} + +fn main() { } diff --git a/src/test/compile-fail/empty-struct-unit-pat.rs b/src/test/compile-fail/empty-struct-unit-pat.rs index a75290c94053d..05733762d37ad 100644 --- a/src/test/compile-fail/empty-struct-unit-pat.rs +++ b/src/test/compile-fail/empty-struct-unit-pat.rs @@ -37,11 +37,11 @@ fn main() { // } match e2 { Empty2(..) => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct - //~^ ERROR hard error + //~^ WARNING hard error } match xe2 { XEmpty2(..) => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct - //~^ ERROR hard error + //~^ WARNING hard error } // Rejected by parser as yet // match e4 { @@ -53,11 +53,11 @@ fn main() { // } match e4 { E::Empty4(..) => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct - //~^ ERROR hard error + //~^ WARNING hard error } match xe4 { XE::XEmpty4(..) => (), //~ ERROR `XE::XEmpty4` does not name a tuple variant or a tuple - //~^ ERROR hard error + //~^ WARNING hard error _ => {}, } } diff --git a/src/test/compile-fail/integer-literal-suffix-inference.rs b/src/test/compile-fail/integer-literal-suffix-inference.rs index 8f04b58b77868..a01db18a34a7f 100644 --- a/src/test/compile-fail/integer-literal-suffix-inference.rs +++ b/src/test/compile-fail/integer-literal-suffix-inference.rs @@ -143,7 +143,7 @@ fn main() { id_i64(a16); //~^ ERROR mismatched types //~| expected `i64` - //~| found i16 + //~| found `i16` id_i64(a32); //~^ ERROR mismatched types //~| expected `i64` diff --git a/src/test/compile-fail/issue-11714.rs b/src/test/compile-fail/issue-11714.rs index 6dde59d4a2e60..998576097a0a0 100644 --- a/src/test/compile-fail/issue-11714.rs +++ b/src/test/compile-fail/issue-11714.rs @@ -9,7 +9,6 @@ // except according to those terms. fn blah() -> i32 { //~ ERROR not all control paths return a value - //~^ HELP run `rustc --explain E0269` to see a detailed explanation 1 ; //~ HELP consider removing this semicolon: diff --git a/src/test/compile-fail/issue-13058.rs b/src/test/compile-fail/issue-13058.rs index b552d7678d563..de578257e4684 100644 --- a/src/test/compile-fail/issue-13058.rs +++ b/src/test/compile-fail/issue-13058.rs @@ -36,5 +36,4 @@ fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool fn main() { check((3, 5)); //~^ ERROR mismatched types -//~| HELP run `rustc --explain E0308` to see a detailed explanation } diff --git a/src/test/compile-fail/issue-13428.rs b/src/test/compile-fail/issue-13428.rs index 5b8ab08aefca1..c771970650d31 100644 --- a/src/test/compile-fail/issue-13428.rs +++ b/src/test/compile-fail/issue-13428.rs @@ -11,7 +11,6 @@ // Regression test for #13428 fn foo() -> String { //~ ERROR not all control paths return a value - //~^ HELP run `rustc --explain E0269` to see a detailed explanation format!("Hello {}", "world") // Put the trailing semicolon on its own line to test that the @@ -20,7 +19,6 @@ fn foo() -> String { //~ ERROR not all control paths return a value } fn bar() -> String { //~ ERROR not all control paths return a value - //~^ HELP run `rustc --explain E0269` to see a detailed explanation "foobar".to_string() ; //~ HELP consider removing this semicolon } diff --git a/src/test/compile-fail/issue-13482.rs b/src/test/compile-fail/issue-13482.rs index 2fbfd6cc84ead..8d98fe313349b 100644 --- a/src/test/compile-fail/issue-13482.rs +++ b/src/test/compile-fail/issue-13482.rs @@ -17,7 +17,7 @@ fn main() { //~^ ERROR mismatched types //~| expected `[_; 2]` //~| found `[_; 0]` - //~| expected array with a fixed size of 2 elements + //~| expected an array with a fixed size of 2 elements [a,_] => Some(a) }; } diff --git a/src/test/compile-fail/issue-13853.rs b/src/test/compile-fail/issue-13853.rs index 7643310298da3..86a6bdfd4dde4 100644 --- a/src/test/compile-fail/issue-13853.rs +++ b/src/test/compile-fail/issue-13853.rs @@ -35,7 +35,7 @@ impl Node for Stuff { fn iterate>(graph: &G) { for node in graph.iter() { //~ ERROR no method named `iter` found - node.zomg(); //~ error: the type of this value must be known in this context + node.zomg(); } } diff --git a/src/test/compile-fail/issue-16747.rs b/src/test/compile-fail/issue-16747.rs index 0fdb5f74e8299..dd7e8a869eca9 100644 --- a/src/test/compile-fail/issue-16747.rs +++ b/src/test/compile-fail/issue-16747.rs @@ -19,7 +19,6 @@ struct List<'a, T: ListItem<'a>> { //~^ ERROR the parameter type `T` may not live long enough //~| HELP consider adding an explicit lifetime bound //~| NOTE ...so that the reference type `&'a [T]` does not outlive the data it points at -//~| HELP run `rustc --explain E0309` to see a detailed explanation } impl<'a, T: ListItem<'a>> Collection for List<'a, T> { fn len(&self) -> usize { diff --git a/src/test/compile-fail/issue-19692.rs b/src/test/compile-fail/issue-19692.rs index 53ad241687894..ca1715445e526 100644 --- a/src/test/compile-fail/issue-19692.rs +++ b/src/test/compile-fail/issue-19692.rs @@ -12,7 +12,7 @@ struct Homura; fn akemi(homura: Homura) { let Some(ref madoka) = Some(homura.kaname()); //~ ERROR no method named `kaname` found - madoka.clone(); //~ ERROR the type of this value must be known + madoka.clone(); } fn main() { } diff --git a/src/test/compile-fail/issue-19707.rs b/src/test/compile-fail/issue-19707.rs index 814c1a4131d38..9affb44b7445c 100644 --- a/src/test/compile-fail/issue-19707.rs +++ b/src/test/compile-fail/issue-19707.rs @@ -13,10 +13,8 @@ type foo = fn(&u8, &u8) -> &u8; //~ ERROR missing lifetime specifier //~^ HELP the signature does not say whether it is borrowed from argument 1 or argument 2 -//~^^ HELP run `rustc --explain E0106` to see a detailed explanation fn bar &u8>(f: &F) {} //~ ERROR missing lifetime specifier //~^ HELP the signature does not say whether it is borrowed from argument 1 or argument 2 -//~^^ HELP run `rustc --explain E0106` to see a detailed explanation fn main() {} diff --git a/src/test/compile-fail/issue-20261.rs b/src/test/compile-fail/issue-20261.rs index 09044b5b5055d..2f1910b26bbef 100644 --- a/src/test/compile-fail/issue-20261.rs +++ b/src/test/compile-fail/issue-20261.rs @@ -11,6 +11,5 @@ fn main() { for (ref i,) in [].iter() { //~ ERROR mismatched types i.clone(); - //~^ ERROR: the type of this value must be known in this context } } diff --git a/src/test/compile-fail/issue-20862.rs b/src/test/compile-fail/issue-20862.rs index 729311416386d..9df6358399869 100644 --- a/src/test/compile-fail/issue-20862.rs +++ b/src/test/compile-fail/issue-20862.rs @@ -10,11 +10,7 @@ fn foo(x: i32) { |y| x + y -//~^ ERROR: mismatched types: -//~| expected `()`, -//~| found closure -//~| (expected (), -//~| found closure) [E0308] +//~^ ERROR: mismatched types } fn main() { diff --git a/src/test/compile-fail/issue-21221-1.rs b/src/test/compile-fail/issue-21221-1.rs index c53d5a0922e64..2bc9ec3289a5d 100644 --- a/src/test/compile-fail/issue-21221-1.rs +++ b/src/test/compile-fail/issue-21221-1.rs @@ -55,7 +55,6 @@ impl Mul for Foo { //~| HELP `mul1::Mul` //~| HELP `mul2::Mul` //~| HELP `std::ops::Mul` -//~| HELP run `rustc --explain E0405` to see a detailed explanation //~| HELP you can import several candidates into scope (`use ...;`): } @@ -77,22 +76,19 @@ fn getMul() -> Mul { //~| HELP `mul3::Mul` //~| HELP `mul4::Mul` //~| HELP and 2 other candidates -//~| HELP run `rustc --explain E0412` to see a detailed explanation //~| HELP you can import several candidates into scope (`use ...;`): } // Let's also test what happens if the trait doesn't exist: impl ThisTraitReallyDoesntExistInAnyModuleReally for Foo { //~^ ERROR trait `ThisTraitReallyDoesntExistInAnyModuleReally` is not in scope -//~^^ HELP run `rustc --explain E0405` to see a detailed explanation -//~^^^ HELP no candidates by the name of `ThisTraitReallyDoesntExistInAnyModuleReally` found +//~| HELP no candidates by the name of `ThisTraitReallyDoesntExistInAnyModuleReally` found } // Let's also test what happens if there's just one alternative: impl Div for Foo { //~^ ERROR trait `Div` is not in scope //~| HELP `use std::ops::Div;` -//~| HELP run `rustc --explain E0405` to see a detailed explanation } fn main() { diff --git a/src/test/compile-fail/issue-21221-2.rs b/src/test/compile-fail/issue-21221-2.rs index cf5c6e8a3b4f0..861acf62d0b58 100644 --- a/src/test/compile-fail/issue-21221-2.rs +++ b/src/test/compile-fail/issue-21221-2.rs @@ -28,4 +28,3 @@ struct Foo; impl T for Foo { } //~^ ERROR trait `T` is not in scope //~| HELP you can import it into scope: `use foo::bar::T;`. -//~| HELP run `rustc --explain E0405` to see a detailed explanation diff --git a/src/test/compile-fail/issue-21221-3.rs b/src/test/compile-fail/issue-21221-3.rs index a1a712d142197..05786e69cefd2 100644 --- a/src/test/compile-fail/issue-21221-3.rs +++ b/src/test/compile-fail/issue-21221-3.rs @@ -25,7 +25,6 @@ struct Foo; impl OuterTrait for Foo {} //~^ ERROR trait `OuterTrait` is not in scope //~| HELP you can import it into scope: `use issue_21221_3::outer::OuterTrait;`. -//~| HELP run `rustc --explain E0405` to see a detailed explanation fn main() { println!("Hello, world!"); } diff --git a/src/test/compile-fail/issue-21221-4.rs b/src/test/compile-fail/issue-21221-4.rs index 1ef205bd8be85..bcbee16cdcf32 100644 --- a/src/test/compile-fail/issue-21221-4.rs +++ b/src/test/compile-fail/issue-21221-4.rs @@ -20,7 +20,6 @@ struct Foo; impl T for Foo {} //~^ ERROR trait `T` is not in scope //~| HELP you can import it into scope: `use issue_21221_4::T;`. -//~| HELP run `rustc --explain E0405` to see a detailed explanation fn main() { println!("Hello, world!"); diff --git a/src/test/compile-fail/issue-21600.rs b/src/test/compile-fail/issue-21600.rs index d9dcebfda6a1d..1d0473ec4b651 100644 --- a/src/test/compile-fail/issue-21600.rs +++ b/src/test/compile-fail/issue-21600.rs @@ -23,8 +23,6 @@ fn main() { call_it(|| x.gen()); call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer //~^ ERROR cannot borrow data mutably in a captured outer - //~^^ HELP run `rustc --explain E0387` to see a detailed explanation - //~^^^ HELP run `rustc --explain E0387` to see a detailed explanation - //~^^^^ HELP consider changing this closure to take self by mutable reference + //~| HELP consider changing this closure to take self by mutable reference }); } diff --git a/src/test/compile-fail/issue-21659-show-relevant-trait-impls-1.rs b/src/test/compile-fail/issue-21659-show-relevant-trait-impls-1.rs index e880a8b212bbc..99035209e14bc 100644 --- a/src/test/compile-fail/issue-21659-show-relevant-trait-impls-1.rs +++ b/src/test/compile-fail/issue-21659-show-relevant-trait-impls-1.rs @@ -36,5 +36,4 @@ fn main() { //~| help: the following implementations were found: //~| help: > //~| help: > - //~| help: run `rustc --explain E0277` } diff --git a/src/test/compile-fail/issue-21659-show-relevant-trait-impls-2.rs b/src/test/compile-fail/issue-21659-show-relevant-trait-impls-2.rs index 2c5b18a8113f7..2009c32c85436 100644 --- a/src/test/compile-fail/issue-21659-show-relevant-trait-impls-2.rs +++ b/src/test/compile-fail/issue-21659-show-relevant-trait-impls-2.rs @@ -43,5 +43,4 @@ fn main() { //~| help: > //~| help: > //~| help: and 2 others - //~| help: run `rustc --explain E0277` } diff --git a/src/test/compile-fail/issue-24036.rs b/src/test/compile-fail/issue-24036.rs index 28eebea749cce..06b058cbfe179 100644 --- a/src/test/compile-fail/issue-24036.rs +++ b/src/test/compile-fail/issue-24036.rs @@ -14,7 +14,6 @@ fn closure_to_loc() { //~^ ERROR mismatched types //~| NOTE no two closures, even if identical, have the same type //~| HELP consider boxing your closure and/or using it as a trait object - //~| HELP run `rustc --explain E0308` to see a detailed explanation } fn closure_from_match() { @@ -27,7 +26,6 @@ fn closure_from_match() { //~^^^^^^ ERROR match arms have incompatible types //~| NOTE no two closures, even if identical, have the same type //~| HELP consider boxing your closure and/or using it as a trait object - //~| HELP run `rustc --explain E0308` to see a detailed explanation } fn main() { } diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index cafe6d1bb5829..a2831fd2b5ac8 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -11,10 +11,6 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR: mismatched types: - //~| expected `std::ops::Fn() -> u32 + 'static`, - //~| found closure - //~| (expected trait std::ops::Fn, - //~| found closure) 0 }; } diff --git a/src/test/compile-fail/issue-26480.rs b/src/test/compile-fail/issue-26480.rs index 903df42291c63..23e4ffb1f3076 100644 --- a/src/test/compile-fail/issue-26480.rs +++ b/src/test/compile-fail/issue-26480.rs @@ -30,8 +30,7 @@ macro_rules! write { } macro_rules! cast { - ($x:expr) => ($x as ()) - //~^ ERROR non-scalar cast: `i32` as `()` + ($x:expr) => ($x as ()) //~ ERROR non-scalar cast } fn main() { diff --git a/src/test/compile-fail/issue-26638.rs b/src/test/compile-fail/issue-26638.rs index 9cbb64c2311bc..f918f0aed7a10 100644 --- a/src/test/compile-fail/issue-26638.rs +++ b/src/test/compile-fail/issue-26638.rs @@ -11,18 +11,15 @@ fn parse_type(iter: Box+'static>) -> &str { iter.next() } //~^ ERROR missing lifetime specifier [E0106] //~^^ HELP 2 elided lifetimes -//~^^^ HELP run `rustc --explain E0106` to see a detailed explanation fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } //~^ ERROR missing lifetime specifier [E0106] //~^^ HELP lifetime cannot be derived -//~^^^ HELP run `rustc --explain E0106` to see a detailed explanation -//~^^^^ HELP consider giving it an explicit bounded or 'static lifetime +//~^^^ HELP consider giving it an explicit bounded or 'static lifetime fn parse_type_3() -> &str { unimplemented!() } //~^ ERROR missing lifetime specifier [E0106] //~^^ HELP no value for it to be borrowed from -//~^^^ HELP run `rustc --explain E0106` to see a detailed explanation -//~^^^^ HELP consider giving it a 'static lifetime +//~^^^ HELP consider giving it a 'static lifetime fn main() {} diff --git a/src/test/compile-fail/issue-30123.rs b/src/test/compile-fail/issue-30123.rs index cfd3cd3af3ebc..ae1320c821f8c 100644 --- a/src/test/compile-fail/issue-30123.rs +++ b/src/test/compile-fail/issue-30123.rs @@ -15,5 +15,5 @@ use issue_30123_aux::*; fn main() { let ug = Graph::::new_undirected(); - //~^ ERR no associated item named `new_undirected` found for type + //~^ ERROR no associated item named `new_undirected` found for type } diff --git a/src/test/compile-fail/issue-30302.rs b/src/test/compile-fail/issue-30302.rs index 56f0b31da0d80..26508a4722425 100644 --- a/src/test/compile-fail/issue-30302.rs +++ b/src/test/compile-fail/issue-30302.rs @@ -18,10 +18,8 @@ fn is_empty(s: Stack) -> bool { Nil => true, //~^ WARN pattern binding `Nil` is named the same as one of the variants of the type `Stack` //~| HELP consider making the path in the pattern qualified: `Stack::Nil` -//~| HELP run `rustc --explain E0170` to see a detailed explanation _ => false //~^ ERROR unreachable pattern -//~| HELP run `rustc --explain E0001` to see a detailed explanation } } diff --git a/src/test/compile-fail/symbol-names/issue-32709.rs b/src/test/compile-fail/issue-32709.rs similarity index 100% rename from src/test/compile-fail/symbol-names/issue-32709.rs rename to src/test/compile-fail/issue-32709.rs diff --git a/src/test/compile-fail/issue-3563.rs b/src/test/compile-fail/issue-3563.rs index 29c1c584eed24..7928c04b9df87 100644 --- a/src/test/compile-fail/issue-3563.rs +++ b/src/test/compile-fail/issue-3563.rs @@ -13,10 +13,6 @@ trait A { || self.b() //~^ ERROR no method named `b` found for type `&Self` in the current scope //~| ERROR mismatched types - //~| expected `()` - //~| found closure - //~| expected () - //~| found closure } } fn main() {} diff --git a/src/test/compile-fail/issue-3973.rs b/src/test/compile-fail/issue-3973.rs index 54eb2a9082955..92456760b0508 100644 --- a/src/test/compile-fail/issue-3973.rs +++ b/src/test/compile-fail/issue-3973.rs @@ -31,5 +31,5 @@ impl ToString_ for Point { fn main() { let p = Point::new(0.0, 0.0); //~^ ERROR no associated item named `new` found for type `Point` in the current scope - println!("{}", p.to_string()); //~ ERROR type of this value must be known + println!("{}", p.to_string()); } diff --git a/src/test/compile-fail/issue-6702.rs b/src/test/compile-fail/issue-6702.rs index 6cb825a9be736..66ed817ffa826 100644 --- a/src/test/compile-fail/issue-6702.rs +++ b/src/test/compile-fail/issue-6702.rs @@ -16,5 +16,4 @@ struct Monster { fn main() { let _m = Monster(); //~ ERROR `Monster` is the name of a struct or //~^ HELP did you mean to write: `Monster { /* fields */ }`? - //~| HELP run `rustc --explain E0423` to see a detailed explanation } diff --git a/src/test/compile-fail/issue-7092.rs b/src/test/compile-fail/issue-7092.rs index 4a278bbdeb04a..4acbcb165ff08 100644 --- a/src/test/compile-fail/issue-7092.rs +++ b/src/test/compile-fail/issue-7092.rs @@ -19,7 +19,7 @@ fn foo(x: Whatever) { //~| found `std::option::Option<_>` //~| expected enum `Whatever` //~| found enum `std::option::Option` - field.access(), //~ ERROR the type of this value must be known in this context + field.access(), } } diff --git a/src/test/compile-fail/keyword-false-as-identifier.rs b/src/test/compile-fail/keyword-false-as-identifier.rs index d875898f8bcc4..60caca3da57ed 100644 --- a/src/test/compile-fail/keyword-false-as-identifier.rs +++ b/src/test/compile-fail/keyword-false-as-identifier.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-test -- FIXME #33010 + // This file was auto-generated using 'src/etc/generate-keyword-tests.py false' fn main() { diff --git a/src/test/compile-fail/keyword-true-as-identifier.rs b/src/test/compile-fail/keyword-true-as-identifier.rs index 048b640c0b311..716a0ebf21cec 100644 --- a/src/test/compile-fail/keyword-true-as-identifier.rs +++ b/src/test/compile-fail/keyword-true-as-identifier.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-test -- FIXME #33010 + // This file was auto-generated using 'src/etc/generate-keyword-tests.py true' fn main() { diff --git a/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs b/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs index be4166e43b504..7355c70ff95e8 100644 --- a/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs +++ b/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs @@ -11,7 +11,6 @@ // Lifetime annotation needed because we have no arguments. fn f() -> &isize { //~ ERROR missing lifetime specifier //~^ HELP there is no value for it to be borrowed from -//~| HELP run `rustc --explain E0106` to see a detailed explanation //~| HELP consider giving it a 'static lifetime panic!() } @@ -19,7 +18,6 @@ fn f() -> &isize { //~ ERROR missing lifetime specifier // Lifetime annotation needed because we have two by-reference parameters. fn g(_x: &isize, _y: &isize) -> &isize { //~ ERROR missing lifetime specifier //~^ HELP the signature does not say whether it is borrowed from `_x` or `_y` -//~| HELP run `rustc --explain E0106` to see a detailed explanation panic!() } @@ -31,13 +29,11 @@ struct Foo<'a> { // and one on the reference. fn h(_x: &Foo) -> &isize { //~ ERROR missing lifetime specifier //~^ HELP the signature does not say which one of `_x`'s 2 elided lifetimes it is borrowed from -//~| HELP run `rustc --explain E0106` to see a detailed explanation panic!() } fn i(_x: isize) -> &isize { //~ ERROR missing lifetime specifier //~^ HELP this function's return type contains a borrowed value -//~| HELP run `rustc --explain E0106` to see a detailed explanation //~| HELP consider giving it an explicit bounded or 'static lifetime panic!() } diff --git a/src/test/compile-fail/lint-change-warnings.rs b/src/test/compile-fail/lint-change-warnings.rs index 441a8410700bf..19e253e3b8e53 100644 --- a/src/test/compile-fail/lint-change-warnings.rs +++ b/src/test/compile-fail/lint-change-warnings.rs @@ -27,5 +27,5 @@ fn bar() { #[forbid(warnings)] fn baz() { - while true {} //~ ERROR: warnings + while true {} //~ ERROR: infinite } diff --git a/src/test/compile-fail/lint-malformed.rs b/src/test/compile-fail/lint-malformed.rs index 592e2b11905b3..ad5e3aa3f0606 100644 --- a/src/test/compile-fail/lint-malformed.rs +++ b/src/test/compile-fail/lint-malformed.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny = "foo"] //~ ERR malformed lint attribute -#![allow(bar = "baz")] //~ ERR malformed lint attribute +#![deny = "foo"] //~ ERROR malformed lint attribute +#![allow(bar = "baz")] //~ ERROR malformed lint attribute fn main() { } diff --git a/src/test/compile-fail/lint-removed-allow.rs b/src/test/compile-fail/lint-removed-allow.rs index 159a3d746034e..1498ed4d17ed7 100644 --- a/src/test/compile-fail/lint-removed-allow.rs +++ b/src/test/compile-fail/lint-removed-allow.rs @@ -14,4 +14,4 @@ #[deny(raw_pointer_derive)] #[allow(renamed_and_removed_lints)] #[deny(unused_variables)] -fn main() { let unused = (); } //~ ERR unused +fn main() { let unused = (); } //~ ERROR unused diff --git a/src/test/compile-fail/lint-removed.rs b/src/test/compile-fail/lint-removed.rs index 9069356604131..aa7f535aa64b7 100644 --- a/src/test/compile-fail/lint-removed.rs +++ b/src/test/compile-fail/lint-removed.rs @@ -15,4 +15,4 @@ #[deny(raw_pointer_derive)] //~ WARN raw_pointer_derive has been removed #[deny(unused_variables)] -fn main() { let unused = (); } //~ ERR unused +fn main() { let unused = (); } //~ ERROR unused diff --git a/src/test/compile-fail/lint-renamed-allow.rs b/src/test/compile-fail/lint-renamed-allow.rs index a2426d80f714d..ea26c3656e691 100644 --- a/src/test/compile-fail/lint-renamed-allow.rs +++ b/src/test/compile-fail/lint-renamed-allow.rs @@ -14,4 +14,4 @@ #[deny(unknown_features)] #[allow(renamed_and_removed_lints)] #[deny(unused)] -fn main() { let unused = (); } //~ ERR unused +fn main() { let unused = (); } //~ ERROR unused diff --git a/src/test/compile-fail/lint-renamed.rs b/src/test/compile-fail/lint-renamed.rs index 2e85a323a1c41..9e10ddf89ac33 100644 --- a/src/test/compile-fail/lint-renamed.rs +++ b/src/test/compile-fail/lint-renamed.rs @@ -10,4 +10,4 @@ #[deny(unknown_features)] //~ WARN lint unknown_features has been renamed to unused_features #[deny(unused)] -fn main() { let unused = (); } //~ ERR unused +fn main() { let unused = (); } //~ ERROR unused diff --git a/src/test/compile-fail/lint-unknown-lint.rs b/src/test/compile-fail/lint-unknown-lint.rs index 8f20a2c8ab758..2de8d849d1915 100644 --- a/src/test/compile-fail/lint-unknown-lint.rs +++ b/src/test/compile-fail/lint-unknown-lint.rs @@ -10,4 +10,4 @@ #![allow(not_a_real_lint)] //~ WARN unknown lint #![deny(unused)] -fn main() { let unused = (); } //~ ERR unused variable +fn main() { let unused = (); } //~ ERROR unused variable diff --git a/src/test/compile-fail/lint-unused-imports.rs b/src/test/compile-fail/lint-unused-imports.rs index 3c1f4b0430621..40322f5a5b53b 100644 --- a/src/test/compile-fail/lint-unused-imports.rs +++ b/src/test/compile-fail/lint-unused-imports.rs @@ -24,6 +24,8 @@ use test::A; //~ ERROR unused import // Be sure that if we just bring some methods into scope that they're also // counted as being used. use test::B; +// But only when actually used: do not get confused by the method with the same name. +use test::B2; //~ ERROR unused import // Make sure this import is warned about when at least one of its imported names // is unused @@ -37,6 +39,7 @@ mod test2 { mod test { pub trait A { fn a(&self) {} } pub trait B { fn b(&self) {} } + pub trait B2 { fn b(&self) {} } pub struct C; impl A for C {} impl B for C {} diff --git a/src/test/compile-fail/liveness-return-last-stmt-semi.rs b/src/test/compile-fail/liveness-return-last-stmt-semi.rs index 343622c5c1b04..03733cc2eb596 100644 --- a/src/test/compile-fail/liveness-return-last-stmt-semi.rs +++ b/src/test/compile-fail/liveness-return-last-stmt-semi.rs @@ -12,19 +12,15 @@ macro_rules! test { () => { fn foo() -> i32 { 1; } } } //~^ ERROR not all control paths return a value - //~^^ HELP consider removing this semicolon - //~^^^ HELP run `rustc --explain E0269` to see a + //~| HELP consider removing this semicolon fn no_return() -> i32 {} //~ ERROR not all control paths return a value - //~^ HELP run `rustc --explain E0269` to see a detailed explanation fn bar(x: u32) -> u32 { //~ ERROR not all control paths return a value - //~^ HELP run `rustc --explain E0269` to see a detailed explanation x * 2; //~ HELP consider removing this semicolon } fn baz(x: u64) -> u32 { //~ ERROR not all control paths return a value - //~^ HELP run `rustc --explain E0269` to see a detailed explanation x * 2; } diff --git a/src/test/compile-fail/privacy/restricted/private-in-public.rs b/src/test/compile-fail/privacy/restricted/private-in-public.rs index f8e7e6283a0af..84328ca387d73 100644 --- a/src/test/compile-fail/privacy/restricted/private-in-public.rs +++ b/src/test/compile-fail/privacy/restricted/private-in-public.rs @@ -15,6 +15,8 @@ mod foo { mod bar { use foo::Priv; pub(super) fn f(_: Priv) {} - pub(crate) fn f(_: Priv) {} //~ ERROR private + pub(crate) fn g(_: Priv) {} //~ ERROR E0446 } } + +fn main() { } diff --git a/src/test/compile-fail/ref-suggestion.rs b/src/test/compile-fail/ref-suggestion.rs index 4625669d5ecfe..815f752663223 100644 --- a/src/test/compile-fail/ref-suggestion.rs +++ b/src/test/compile-fail/ref-suggestion.rs @@ -14,14 +14,12 @@ fn main() { //~^ HELP use a `ref` binding as shown //~| SUGGESTION let ref y = x; x; //~ ERROR use of moved value - //~^ HELP run `rustc --explain E0382` to see a detailed explanation let x = vec![1]; let mut y = x; //~^ HELP use a `ref` binding as shown //~| SUGGESTION let ref mut y = x; x; //~ ERROR use of moved value - //~^ HELP run `rustc --explain E0382` to see a detailed explanation let x = (Some(vec![1]), ()); @@ -32,5 +30,4 @@ fn main() { _ => {}, } x; //~ ERROR use of partially moved value - //~^ HELP run `rustc --explain E0382` to see a detailed explanation } diff --git a/src/test/compile-fail/substs-ppaux.rs b/src/test/compile-fail/substs-ppaux.rs index 851e31b942ed1..8dd9994b234ba 100644 --- a/src/test/compile-fail/substs-ppaux.rs +++ b/src/test/compile-fail/substs-ppaux.rs @@ -28,7 +28,7 @@ fn foo<'z>() where &'z (): Sized { //[verbose]~| found `fn() {>::bar::}` //[normal]~^^^^ ERROR mismatched types //[normal]~| expected `()` - //[normal]~| found `fn() {>::bar::<'static, char>}` + //[normal]~| found `fn() {>::bar::<'static, char>}` let x: () = >::bar::<'static, char>; diff --git a/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs b/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs index 8877377a6ec96..1d04679fd11e7 100644 --- a/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs +++ b/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs @@ -27,54 +27,46 @@ fn h1() -> i32 { a.I //~^ ERROR E0425 //~| HELP To reference an item from the `a` module, use `a::I` - //~| HELP run `rustc --explain E0425` to see a detailed explanation } fn h2() -> i32 { a.g() //~^ ERROR E0425 //~| HELP To call a function from the `a` module, use `a::g(..)` - //~| HELP run `rustc --explain E0425` to see a detailed explanation } fn h3() -> i32 { a.b.J //~^ ERROR E0425 //~| HELP To reference an item from the `a` module, use `a::b` - //~| HELP run `rustc --explain E0425` to see a detailed explanation } fn h4() -> i32 { a::b.J //~^ ERROR E0425 //~| HELP To reference an item from the `a::b` module, use `a::b::J` - //~| HELP run `rustc --explain E0425` to see a detailed explanation } fn h5() -> i32 { a.b.f() //~^ ERROR E0425 //~| HELP To reference an item from the `a` module, use `a::b` - //~| HELP run `rustc --explain E0425` to see a detailed explanation } fn h6() -> i32 { a::b.f() //~^ ERROR E0425 //~| HELP To call a function from the `a::b` module, use `a::b::f(..)` - //~| HELP run `rustc --explain E0425` to see a detailed explanation } fn h7() { a::b //~^ ERROR E0425 //~| HELP Module `a::b` cannot be the value of an expression - //~| HELP run `rustc --explain E0425` to see a detailed explanation } fn h8() -> i32 { a::b() //~^ ERROR E0425 //~| HELP No function corresponds to `a::b(..)` - //~| HELP run `rustc --explain E0425` to see a detailed explanation } diff --git a/src/test/compile-fail/trait-bounds-impl-comparison-1.rs b/src/test/compile-fail/trait-bounds-impl-comparison-1.rs index 3fffb2e19f289..9cf65a9d00d07 100644 --- a/src/test/compile-fail/trait-bounds-impl-comparison-1.rs +++ b/src/test/compile-fail/trait-bounds-impl-comparison-1.rs @@ -74,7 +74,7 @@ trait Trait { impl Trait for usize { fn method>(&self) {} - //~^ G : Getter` appears on the impl method but not on the corresponding trait method + //~^ ERROR `G: Getter` appears on the impl method } fn main() {} diff --git a/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs b/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs index 29360e58b5bd3..fc2ed83b2724d 100644 --- a/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs +++ b/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs @@ -13,10 +13,8 @@ fn main() { //~^ ERROR expected a path //~| HELP try adding parentheses //~| SUGGESTION let _: &(Copy + 'static); - //~| HELP run `rustc --explain E0178` to see a detailed explanation let _: &'static Copy + 'static; //~^ ERROR expected a path //~| HELP try adding parentheses //~| SUGGESTION let _: &'static (Copy + 'static); - //~| HELP run `rustc --explain E0178` to see a detailed explanation } diff --git a/src/test/compile-fail/trait-suggest-where-clause.rs b/src/test/compile-fail/trait-suggest-where-clause.rs index 6950bce7304c0..a8ff1bae7a71a 100644 --- a/src/test/compile-fail/trait-suggest-where-clause.rs +++ b/src/test/compile-fail/trait-suggest-where-clause.rs @@ -16,13 +16,11 @@ fn check() { // suggest a where-clause, if needed mem::size_of::(); //~^ ERROR `U: std::marker::Sized` is not satisfied - //~| HELP E0277 //~| HELP consider adding a `where U: std::marker::Sized` bound //~| NOTE required by `std::mem::size_of` mem::size_of::>(); //~^ ERROR `U: std::marker::Sized` is not satisfied - //~| HELP E0277 //~| HELP consider adding a `where U: std::marker::Sized` bound //~| NOTE required because it appears within the type `Misc` //~| NOTE required by `std::mem::size_of` @@ -31,13 +29,11 @@ fn check() { >::from; //~^ ERROR `u64: std::convert::From` is not satisfied - //~| HELP E0277 //~| HELP consider adding a `where u64: std::convert::From` bound //~| NOTE required by `std::convert::From::from` ::Item>>::from; //~^ ERROR `u64: std::convert::From<::Item>` is not satisfied - //~| HELP E0277 //~| HELP consider adding a `where u64: //~| NOTE required by `std::convert::From::from` @@ -45,20 +41,17 @@ fn check() { as From>::from; //~^ ERROR `Misc<_>: std::convert::From` is not satisfied - //~| HELP E0277 //~| NOTE required by `std::convert::From::from` // ... and also not if the error is not related to the type mem::size_of::<[T]>(); //~^ ERROR `[T]: std::marker::Sized` is not satisfied - //~| HELP E0277 //~| NOTE `[T]` does not have a constant size //~| NOTE required by `std::mem::size_of` mem::size_of::<[&U]>(); //~^ ERROR `[&U]: std::marker::Sized` is not satisfied - //~| HELP E0277 //~| NOTE `[&U]` does not have a constant size //~| NOTE required by `std::mem::size_of` } diff --git a/src/test/compile-fail/transmute-from-fn-item-types-lint.rs b/src/test/compile-fail/transmute-from-fn-item-types-lint.rs index 42c3cb7f18131..08e660e878c29 100644 --- a/src/test/compile-fail/transmute-from-fn-item-types-lint.rs +++ b/src/test/compile-fail/transmute-from-fn-item-types-lint.rs @@ -15,15 +15,15 @@ use std::mem; unsafe fn foo() -> (isize, *const (), Option) { let i = mem::transmute(bar); //~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting - //~^^ ERROR was previously accepted + //~^^ WARNING was previously accepted let p = mem::transmute(foo); //~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting - //~^^ ERROR was previously accepted + //~^^ WARNING was previously accepted let of = mem::transmute(main); //~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting - //~^^ ERROR was previously accepted + //~^^ WARNING was previously accepted (i, p, of) } @@ -31,11 +31,11 @@ unsafe fn foo() -> (isize, *const (), Option) { unsafe fn bar() { mem::transmute::<_, *mut ()>(foo); //~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting - //~^^ ERROR was previously accepted + //~^^ WARNING was previously accepted mem::transmute::<_, fn()>(bar); //~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting - //~^^ ERROR was previously accepted + //~^^ WARNING was previously accepted // No error if a coercion would otherwise occur. mem::transmute::(main); diff --git a/src/test/compile-fail/type-mismatch-same-crate-name.rs b/src/test/compile-fail/type-mismatch-same-crate-name.rs index 014fa35c309e6..e81ae5d743939 100644 --- a/src/test/compile-fail/type-mismatch-same-crate-name.rs +++ b/src/test/compile-fail/type-mismatch-same-crate-name.rs @@ -24,10 +24,8 @@ fn main() { { extern crate crate_a1 as a; a::try_foo(foo2); //~ ERROR mismatched types - //~^ HELP run - //~^^ NOTE Perhaps two different versions of crate `crate_a1` + //~^ NOTE Perhaps two different versions of crate `crate_a1` a::try_bar(bar2); //~ ERROR mismatched types - //~^ HELP run - //~^^ NOTE Perhaps two different versions of crate `crate_a1` + //~^ NOTE Perhaps two different versions of crate `crate_a1` } } diff --git a/src/test/compile-fail/variance-unused-type-param.rs b/src/test/compile-fail/variance-unused-type-param.rs index f7fed32cb5af2..862d842d62c23 100644 --- a/src/test/compile-fail/variance-unused-type-param.rs +++ b/src/test/compile-fail/variance-unused-type-param.rs @@ -16,18 +16,15 @@ struct SomeStruct { x: u32 } //~^ ERROR parameter `A` is never used //~| HELP PhantomData -//~| HELP run `rustc --explain E0392` to see a detailed explanation enum SomeEnum { Nothing } //~^ ERROR parameter `A` is never used //~| HELP PhantomData -//~| HELP run `rustc --explain E0392` to see a detailed explanation // Here T might *appear* used, but in fact it isn't. enum ListCell { //~^ ERROR parameter `T` is never used //~| HELP PhantomData -//~| HELP run `rustc --explain E0392` to see a detailed explanation Cons(Box>), Nil } diff --git a/src/test/parse-fail/column-offset-1-based.rs b/src/test/parse-fail/column-offset-1-based.rs index bcadd1f39fa98..8caf2e0c0a477 100644 --- a/src/test/parse-fail/column-offset-1-based.rs +++ b/src/test/parse-fail/column-offset-1-based.rs @@ -10,4 +10,4 @@ // compile-flags: -Z parse-only -# //~ ERROR 13:1: 13:2 error: expected `[`, found `` +# //~ ERROR 13:1: 13:2: expected `[`, found `` diff --git a/src/test/run-make/json-errors/Makefile b/src/test/run-make/json-errors/Makefile index bb73fda67bddb..30bcafd104945 100644 --- a/src/test/run-make/json-errors/Makefile +++ b/src/test/run-make/json-errors/Makefile @@ -6,5 +6,4 @@ all: cp foo.rs $(TMPDIR) cd $(TMPDIR) -$(RUSTC) -Z unstable-options --error-format=json foo.rs 2>$(LOG) - grep -q '{"message":"unresolved name `y`","code":{"code":"E0425","explanation":"\\nAn unresolved name was used. Example of erroneous codes.*"},"level":"error","spans":\[{"file_name":"foo.rs","byte_start":496,"byte_end":497,"line_start":12,"line_end":12,"column_start":18,"column_end":19,"text":\[{"text":" let x = 42 + y;","highlight_start":18,"highlight_end":19}\]}\],"children":\[\]}' $(LOG) - grep -q '{"message":".*","code":{"code":"E0277","explanation":"\\nYou tried.*"},"level":"error","spans":\[{.*}\],"children":\[{"message":"the .*","code":null,"level":"help","spans":\[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":0,"column_end":0,"text":\[{.*}\]}\],"children":\[\]},{"message":" ","code":null,"level":"help",' $(LOG) + diff foo.json $(LOG) diff --git a/src/test/run-make/json-errors/foo.json b/src/test/run-make/json-errors/foo.json new file mode 100644 index 0000000000000..bde669ab0f7f9 --- /dev/null +++ b/src/test/run-make/json-errors/foo.json @@ -0,0 +1,4 @@ +{"message":"unresolved name `y`","code":{"code":"E0425","explanation":"\nAn unresolved name was used. Example of erroneous codes:\n\n```compile_fail\nsomething_that_doesnt_exist::foo;\n// error: unresolved name `something_that_doesnt_exist::foo`\n\n// or:\n\ntrait Foo {\n fn bar() {\n Self; // error: unresolved name `Self`\n }\n}\n\n// or:\n\nlet x = unknown_variable; // error: unresolved name `unknown_variable`\n```\n\nPlease verify that the name wasn't misspelled and ensure that the\nidentifier being referred to is valid for the given situation. Example:\n\n```\nenum something_that_does_exist {\n Foo,\n}\n```\n\nOr:\n\n```\nmod something_that_does_exist {\n pub static foo : i32 = 0i32;\n}\n\nsomething_that_does_exist::foo; // ok!\n```\n\nOr:\n\n```\nlet unknown_variable = 12u32;\nlet x = unknown_variable; // ok!\n```\n"},"level":"error","spans":[{"file_name":"foo.rs","byte_start":496,"byte_end":497,"line_start":12,"line_end":12,"column_start":18,"column_end":19,"text":[{"text":" let x = 42 + y;","highlight_start":18,"highlight_end":19}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null} +{"message":"mismatched types:\n expected `u8`,\n found `i32`","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n\nAnother situation in which this occurs is when you attempt to use the `try!`\nmacro inside a function that does not return a `Result`:\n\n```compile_fail\nuse std::fs::File;\n\nfn main() {\n let mut f = try!(File::create(\"foo.txt\"));\n}\n```\n\nThis code gives an error like this:\n\n```text\n:5:8: 6:42 error: mismatched types:\n expected `()`,\n found `core::result::Result<_, _>`\n (expected (),\n found enum `core::result::Result`) [E0308]\n```\n\n`try!` returns a `Result`, and so the function must. But `main()` has\n`()` as its return type, hence the error.\n"},"level":"error","spans":[{"file_name":"foo.rs","byte_start":511,"byte_end":516,"line_start":14,"line_end":14,"column_start":12,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":12,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null} +{"message":"the trait bound `u8: std::ops::Add` is not satisfied","code":{"code":"E0277","explanation":"\nYou tried to use a type which doesn't implement some trait in a place which\nexpected that trait. Erroneous code example:\n\n```compile_fail\n// here we declare the Foo trait with a bar method\ntrait Foo {\n fn bar(&self);\n}\n\n// we now declare a function which takes an object implementing the Foo trait\nfn some_func(foo: T) {\n foo.bar();\n}\n\nfn main() {\n // we now call the method with the i32 type, which doesn't implement\n // the Foo trait\n some_func(5i32); // error: the trait bound `i32 : Foo` is not satisfied\n}\n```\n\nIn order to fix this error, verify that the type you're using does implement\nthe trait. Example:\n\n```\ntrait Foo {\n fn bar(&self);\n}\n\nfn some_func(foo: T) {\n foo.bar(); // we can now use this method since i32 implements the\n // Foo trait\n}\n\n// we implement the trait on the i32 type\nimpl Foo for i32 {\n fn bar(&self) {}\n}\n\nfn main() {\n some_func(5i32); // ok!\n}\n```\n\nOr in a generic context, an erroneous code example would look like:\n```compile_fail\nfn some_func(foo: T) {\n println!(\"{:?}\", foo); // error: the trait `core::fmt::Debug` is not\n // implemented for the type `T`\n}\n\nfn main() {\n // We now call the method with the i32 type,\n // which *does* implement the Debug trait.\n some_func(5i32);\n}\n```\n\nNote that the error here is in the definition of the generic function: Although\nwe only call it with a parameter that does implement `Debug`, the compiler\nstill rejects the function: It must work with all possible input types. In\norder to make this example compile, we need to restrict the generic type we're\naccepting:\n```\nuse std::fmt;\n\n// Restrict the input type to types that implement Debug.\nfn some_func(foo: T) {\n println!(\"{:?}\", foo);\n}\n\nfn main() {\n // Calling the method is still fine, as i32 implements Debug.\n some_func(5i32);\n\n // This would fail to compile now:\n // struct WithoutDebug;\n // some_func(WithoutDebug);\n}\n\nRust only looks at the signature of the called function, as such it must\nalready specify all requirements that will be used for every type parameter.\n```\n\n"},"level":"error","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[{"message":"the following implementations were found:","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":" ","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":" <&'a u8 as std::ops::Add>","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":" >","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":" <&'b u8 as std::ops::Add<&'a u8>>","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null}],"rendered":null} +{"message":"aborting due to 2 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":null} diff --git a/src/test/parse-fail/keyword-do-as-identifier.rs b/src/test/run-pass/cast-to-infer-ty.rs similarity index 63% rename from src/test/parse-fail/keyword-do-as-identifier.rs rename to src/test/run-pass/cast-to-infer-ty.rs index 5cc14dfef0ec6..2aa0d9c62fb41 100644 --- a/src/test/parse-fail/keyword-do-as-identifier.rs +++ b/src/test/run-pass/cast-to-infer-ty.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// Check that we allow a cast to `_` so long as the target type can be +// inferred elsewhere. -fn main() { - let do = "bar"; //~ error: ident +pub fn main() { + let i: *const i32 = 0 as _; + assert!(i.is_null()); } diff --git a/src/tools/compiletest/Cargo.lock b/src/tools/compiletest/Cargo.lock index 3b79636a2db5b..24c8b20fdf8d7 100644 --- a/src/tools/compiletest/Cargo.lock +++ b/src/tools/compiletest/Cargo.lock @@ -4,6 +4,7 @@ version = "0.0.0" dependencies = [ "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serialize 0.0.0", ] [[package]] @@ -28,6 +29,10 @@ name = "libc" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "log" +version = "0.0.0" + [[package]] name = "log" version = "0.3.6" @@ -63,6 +68,13 @@ name = "regex-syntax" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "serialize" +version = "0.0.0" +dependencies = [ + "log 0.0.0", +] + [[package]] name = "utf8-ranges" version = "0.1.3" diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 359efe8af62e9..573ee38886693 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -13,3 +13,4 @@ opt-level = 2 [dependencies] log = "0.3" env_logger = "0.3" +serialize = { path = "../../libserialize" } \ No newline at end of file diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 6ffc1e9ea1118..81265f6ccafca 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -83,8 +83,11 @@ pub struct Config { // The rustdoc executable pub rustdoc_path: PathBuf, - // The python executable - pub python: String, + // The python executable to use for LLDB + pub lldb_python: String, + + // The python executable to use for htmldocck + pub docck_python: String, // The llvm FileCheck binary path pub llvm_filecheck: Option, diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index 418a0bc7121cb..c3da891933f6d 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -28,7 +28,9 @@ pub enum ErrorKind { impl FromStr for ErrorKind { type Err = (); fn from_str(s: &str) -> Result { - match &s.trim_right_matches(':') as &str { + let s = s.to_uppercase(); + let part0: &str = s.split(':').next().unwrap(); + match part0 { "HELP" => Ok(ErrorKind::Help), "ERROR" => Ok(ErrorKind::Error), "NOTE" => Ok(ErrorKind::Note), @@ -52,7 +54,8 @@ impl fmt::Display for ErrorKind { } } -pub struct ExpectedError { +#[derive(Debug)] +pub struct Error { pub line_num: usize, /// What kind of message we expect (e.g. warning, error, suggestion). /// `None` if not specified or unknown message kind. @@ -73,7 +76,7 @@ enum WhichLine { ThisLine, FollowPrevious(usize), AdjustBackward(usize) } /// /// If cfg is not None (i.e., in an incremental test), then we look /// for `//[X]~` instead, where `X` is the current `cfg`. -pub fn load_errors(testfile: &Path, cfg: Option<&str>) -> Vec { +pub fn load_errors(testfile: &Path, cfg: Option<&str>) -> Vec { let rdr = BufReader::new(File::open(testfile).unwrap()); // `last_nonfollow_error` tracks the most recently seen @@ -113,7 +116,7 @@ fn parse_expected(last_nonfollow_error: Option, line_num: usize, line: &str, tag: &str) - -> Option<(WhichLine, ExpectedError)> { + -> Option<(WhichLine, Error)> { let start = match line.find(tag) { Some(i) => i, None => return None }; let (follow, adjusts) = if line[start + tag.len()..].chars().next().unwrap() == '|' { (true, 0) @@ -121,15 +124,30 @@ fn parse_expected(last_nonfollow_error: Option, (false, line[start + tag.len()..].chars().take_while(|c| *c == '^').count()) }; let kind_start = start + tag.len() + adjusts + (follow as usize); - let kind = line[kind_start..].split_whitespace() - .next() - .expect("Encountered unexpected empty comment") - .parse::() - .ok(); - let letters = line[kind_start..].chars(); - let msg = letters.skip_while(|c| c.is_whitespace()) - .skip_while(|c| !c.is_whitespace()) - .collect::().trim().to_owned(); + let (kind, msg); + match + line[kind_start..].split_whitespace() + .next() + .expect("Encountered unexpected empty comment") + .parse::() + { + Ok(k) => { + // If we find `//~ ERROR foo` or something like that: + kind = Some(k); + let letters = line[kind_start..].chars(); + msg = letters.skip_while(|c| c.is_whitespace()) + .skip_while(|c| !c.is_whitespace()) + .collect::(); + } + Err(_) => { + // Otherwise we found `//~ foo`: + kind = None; + let letters = line[kind_start..].chars(); + msg = letters.skip_while(|c| c.is_whitespace()) + .collect::(); + } + } + let msg = msg.trim().to_owned(); let (which, line_num) = if follow { assert!(adjusts == 0, "use either //~| or //~^, not both."); @@ -145,7 +163,7 @@ fn parse_expected(last_nonfollow_error: Option, debug!("line={} tag={:?} which={:?} kind={:?} msg={:?}", line_num, tag, which, kind, msg); - Some((which, ExpectedError { line_num: line_num, - kind: kind, - msg: msg, })) + Some((which, Error { line_num: line_num, + kind: kind, + msg: msg, })) } diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs new file mode 100644 index 0000000000000..073b5e57cc7c5 --- /dev/null +++ b/src/tools/compiletest/src/json.rs @@ -0,0 +1,197 @@ +// Copyright 2012-2015 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 errors::{Error, ErrorKind}; +use rustc_serialize::json; +use std::str::FromStr; +use std::path::Path; + +// These structs are a subset of the ones found in +// `syntax::errors::json`. + +#[derive(RustcEncodable, RustcDecodable)] +struct Diagnostic { + message: String, + code: Option, + level: String, + spans: Vec, + children: Vec, + rendered: Option, +} + +#[derive(RustcEncodable, RustcDecodable, Clone)] +struct DiagnosticSpan { + file_name: String, + line_start: usize, + line_end: usize, + column_start: usize, + column_end: usize, + expansion: Option>, +} + +#[derive(RustcEncodable, RustcDecodable, Clone)] +struct DiagnosticSpanMacroExpansion { + /// span where macro was applied to generate this code + span: DiagnosticSpan, + + /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]") + macro_decl_name: String, +} + +#[derive(RustcEncodable, RustcDecodable, Clone)] +struct DiagnosticCode { + /// The code itself. + code: String, + /// An explanation for the code. + explanation: Option, +} + +pub fn parse_output(file_name: &str, output: &str) -> Vec { + output.lines() + .flat_map(|line| parse_line(file_name, line)) + .collect() +} + +fn parse_line(file_name: &str, line: &str) -> Vec { + // The compiler sometimes intermingles non-JSON stuff into the + // output. This hack just skips over such lines. Yuck. + if line.chars().next() == Some('{') { + match json::decode::(line) { + Ok(diagnostic) => { + let mut expected_errors = vec![]; + push_expected_errors(&mut expected_errors, &diagnostic, file_name); + expected_errors + } + Err(error) => { + panic!("failed to decode compiler output as json: `{}`", error); + } + } + } else { + vec![] + } +} + +fn push_expected_errors(expected_errors: &mut Vec, + diagnostic: &Diagnostic, + file_name: &str) { + // We only consider messages pertaining to the current file. + let matching_spans = || { + diagnostic.spans.iter().filter(|span| { + Path::new(&span.file_name) == Path::new(&file_name) + }) + }; + + // We break the output into multiple lines, and then append the + // [E123] to every line in the output. This may be overkill. The + // intention was to match existing tests that do things like "//| + // found `i32` [E123]" and expect to match that somewhere, and yet + // also ensure that `//~ ERROR E123` *always* works. The + // assumption is that these multi-line error messages are on their + // way out anyhow. + let with_code = |span: &DiagnosticSpan, text: &str| { + match diagnostic.code { + Some(ref code) => + // FIXME(#33000) -- it'd be better to use a dedicated + // UI harness than to include the line/col number like + // this, but some current tests rely on it. + // + // Note: Do NOT include the filename. These can easily + // cause false matches where the expected message + // appears in the filename, and hence the message + // changes but the test still passes. + format!("{}:{}: {}:{}: {} [{}]", + span.line_start, span.column_start, + span.line_end, span.column_end, + text, code.code.clone()), + None => + // FIXME(#33000) -- it'd be better to use a dedicated UI harness + format!("{}:{}: {}:{}: {}", + span.line_start, span.column_start, + span.line_end, span.column_end, + text), + } + }; + + // Convert multi-line messages into multiple expected + // errors. We expect to replace these with something + // more structured shortly anyhow. + let mut message_lines = diagnostic.message.lines(); + if let Some(first_line) = message_lines.next() { + for span in matching_spans() { + let msg = with_code(span, first_line); + let kind = ErrorKind::from_str(&diagnostic.level).ok(); + expected_errors.push( + Error { + line_num: span.line_start, + kind: kind, + msg: msg, + } + ); + } + } + for next_line in message_lines { + for span in matching_spans() { + expected_errors.push( + Error { + line_num: span.line_start, + kind: None, + msg: with_code(span, next_line), + } + ); + } + } + + // If the message has a suggestion, register that. + if let Some(ref rendered) = diagnostic.rendered { + let start_line = matching_spans().map(|s| s.line_start).min().expect("\ + every suggestion should have at least one span"); + for (index, line) in rendered.lines().enumerate() { + expected_errors.push( + Error { + line_num: start_line + index, + kind: Some(ErrorKind::Suggestion), + msg: line.to_string() + } + ); + } + } + + // Add notes for the backtrace + for span in matching_spans() { + for frame in &span.expansion { + push_backtrace(expected_errors, + frame, + file_name); + } + } + + // Flatten out the children. + for child in &diagnostic.children { + push_expected_errors(expected_errors, child, file_name); + } +} + +fn push_backtrace(expected_errors: &mut Vec, + expansion: &DiagnosticSpanMacroExpansion, + file_name: &str) { + if Path::new(&expansion.span.file_name) == Path::new(&file_name) { + expected_errors.push( + Error { + line_num: expansion.span.line_start, + kind: Some(ErrorKind::Note), + msg: format!("in this expansion of {}", expansion.macro_decl_name), + } + ); + } + + for previous_expansion in &expansion.span.expansion { + push_backtrace(expected_errors, previous_expansion, file_name); + } +} diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index e92b0c8728099..a9810099dbf9b 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -21,6 +21,7 @@ extern crate libc; extern crate test; extern crate getopts; +extern crate serialize as rustc_serialize; #[macro_use] extern crate log; @@ -40,6 +41,7 @@ use util::logv; pub mod procsrv; pub mod util; +mod json; pub mod header; pub mod runtest; pub mod common; @@ -70,7 +72,8 @@ pub fn parse_config(args: Vec ) -> Config { reqopt("", "run-lib-path", "path to target shared libraries", "PATH"), reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"), reqopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH"), - reqopt("", "python", "path to python to use for doc tests", "PATH"), + reqopt("", "lldb-python", "path to python to use for doc tests", "PATH"), + reqopt("", "docck-python", "path to python to use for doc tests", "PATH"), optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM"), optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind"), optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR"), @@ -140,7 +143,8 @@ pub fn parse_config(args: Vec ) -> Config { run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), rustc_path: opt_path(matches, "rustc-path"), rustdoc_path: opt_path(matches, "rustdoc-path"), - python: matches.opt_str("python").unwrap(), + lldb_python: matches.opt_str("lldb-python").unwrap(), + docck_python: matches.opt_str("docck-python").unwrap(), valgrind_path: matches.opt_str("valgrind-path"), force_valgrind: matches.opt_present("force-valgrind"), llvm_filecheck: matches.opt_str("llvm-filecheck").map(|s| PathBuf::from(&s)), diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 6358d19ff0906..e0abf8200a0bb 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -12,7 +12,8 @@ use common::Config; use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind}; use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits}; use common::{Incremental}; -use errors::{self, ErrorKind}; +use errors::{self, ErrorKind, Error}; +use json; use header::TestProps; use header; use procsrv; @@ -26,7 +27,7 @@ use std::fs::{self, File}; use std::io::BufReader; use std::io::prelude::*; use std::net::TcpStream; -use std::path::{Path, PathBuf, Component}; +use std::path::{Path, PathBuf}; use std::process::{Command, Output, ExitStatus}; pub fn run(config: Config, testpaths: &TestPaths) { @@ -776,7 +777,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testpaths: &TestP let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py"); cmd2procres(config, testpaths, - Command::new(&config.python) + Command::new(&config.lldb_python) .arg(&lldb_script_path) .arg(test_executable) .arg(debugger_script) @@ -944,7 +945,7 @@ fn check_error_patterns(revision: Option<&str>, testpaths.file.display())); } let mut next_err_idx = 0; - let mut next_err_pat = &props.error_patterns[next_err_idx]; + let mut next_err_pat = props.error_patterns[next_err_idx].trim(); let mut done = false; for line in output_to_check.lines() { if line.contains(next_err_pat) { @@ -955,7 +956,7 @@ fn check_error_patterns(revision: Option<&str>, done = true; break; } - next_err_pat = &props.error_patterns[next_err_idx]; + next_err_pat = props.error_patterns[next_err_idx].trim(); } } if done { return; } @@ -998,208 +999,110 @@ fn check_forbid_output(revision: Option<&str>, } fn check_expected_errors(revision: Option<&str>, - expected_errors: Vec, + expected_errors: Vec, testpaths: &TestPaths, proc_res: &ProcRes) { - // true if we found the error in question - let mut found_flags = vec![false; expected_errors.len()]; - if proc_res.status.success() { fatal_proc_rec(revision, "process did not return an error status", proc_res); } - let prefixes = expected_errors.iter().map(|ee| { - let expected = format!("{}:{}:", testpaths.file.display(), ee.line_num); - // On windows just translate all '\' path separators to '/' - expected.replace(r"\", "/") - }).collect::>(); + let file_name = + format!("{}", testpaths.file.display()) + .replace(r"\", "/"); // on windows, translate all '\' path separators to '/' // If the testcase being checked contains at least one expected "help" // message, then we'll ensure that all "help" messages are expected. // Otherwise, all "help" messages reported by the compiler will be ignored. // This logic also applies to "note" messages. - let (expect_help, expect_note) = - expected_errors.iter() - .fold((false, false), - |(acc_help, acc_note), ee| - (acc_help || ee.kind == Some(ErrorKind::Help), - acc_note || ee.kind == Some(ErrorKind::Note))); - - // Scan and extract our error/warning messages, - // which look like: - // filename:line1:col1: line2:col2: *error:* msg - // filename:line1:col1: line2:col2: *warning:* msg - // where line1:col1: is the starting point, line2:col2: - // is the ending point, and * represents ANSI color codes. - // - // This pattern is ambiguous on windows, because filename may contain - // a colon, so any path prefix must be detected and removed first. + let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help)); + let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note)); + + // Parse the JSON output from the compiler and extract out the messages. + let actual_errors = json::parse_output(&file_name, &proc_res.stderr); let mut unexpected = 0; let mut not_found = 0; - for line in proc_res.stderr.lines() { - let mut was_expected = false; - let mut prev = 0; - for (i, ee) in expected_errors.iter().enumerate() { - if !found_flags[i] { - debug!("prefix={} ee.kind={:?} ee.msg={} line={}", - prefixes[i], - ee.kind, - ee.msg, - line); - // Suggestions have no line number in their output, so take on the line number of - // the previous expected error - if ee.kind == Some(ErrorKind::Suggestion) { - assert!(expected_errors[prev].kind == Some(ErrorKind::Help), - "SUGGESTIONs must be preceded by a HELP"); - if line.contains(&ee.msg) { - found_flags[i] = true; - was_expected = true; - break; - } - } - if - (prefix_matches(line, &prefixes[i]) || continuation(line)) && - (ee.kind.is_none() || line.contains(&ee.kind.as_ref().unwrap().to_string())) && - line.contains(&ee.msg) - { - found_flags[i] = true; - was_expected = true; - break; - } + let mut found = vec![false; expected_errors.len()]; + for actual_error in &actual_errors { + let opt_index = + expected_errors + .iter() + .enumerate() + .position(|(index, expected_error)| { + !found[index] && + actual_error.line_num == expected_error.line_num && + (expected_error.kind.is_none() || + actual_error.kind == expected_error.kind) && + actual_error.msg.contains(&expected_error.msg) + }); + + match opt_index { + Some(index) => { + // found a match, everybody is happy + assert!(!found[index]); + found[index] = true; } - prev = i; - } - - // ignore this msg which gets printed at the end - if line.contains("aborting due to") { - was_expected = true; - } - if !was_expected && is_unexpected_compiler_message(line, expect_help, expect_note) { - error(revision, &format!("unexpected compiler message: '{}'", line)); - unexpected += 1; + None => { + if is_unexpected_compiler_message(actual_error, + expect_help, + expect_note) { + error(revision, + &format!("{}:{}: unexpected {:?}: '{}'", + file_name, + actual_error.line_num, + actual_error.kind.as_ref() + .map_or(String::from("message"), + |k| k.to_string()), + actual_error.msg)); + unexpected += 1; + } + } } } - for (i, &flag) in found_flags.iter().enumerate() { - if !flag { - let ee = &expected_errors[i]; - error(revision, &format!("expected {} on line {} not found: {}", - ee.kind.as_ref() - .map_or("message".into(), - |k| k.to_string()), - ee.line_num, ee.msg)); + // anything not yet found is a problem + for (index, expected_error) in expected_errors.iter().enumerate() { + if !found[index] { + error(revision, + &format!("{}:{}: expected {} not found: {}", + file_name, + expected_error.line_num, + expected_error.kind.as_ref() + .map_or("message".into(), + |k| k.to_string()), + expected_error.msg)); not_found += 1; } } if unexpected > 0 || not_found > 0 { - fatal_proc_rec( - revision, - &format!("{} unexpected errors found, {} expected errors not found", - unexpected, not_found), - proc_res); - } - - fn prefix_matches(line: &str, prefix: &str) -> bool { - use std::ascii::AsciiExt; - // On windows just translate all '\' path separators to '/' - let line = line.replace(r"\", "/"); - if cfg!(windows) { - line.to_ascii_lowercase().starts_with(&prefix.to_ascii_lowercase()) - } else { - line.starts_with(prefix) - } - } - - // A multi-line error will have followup lines which start with a space - // or open paren. - fn continuation( line: &str) -> bool { - line.starts_with(" ") || line.starts_with("(") - } -} - -fn is_unexpected_compiler_message(line: &str, expect_help: bool, expect_note: bool) -> bool { - let mut c = Path::new(line).components(); - let line = match c.next() { - Some(Component::Prefix(_)) => c.as_path().to_str().unwrap(), - _ => line, - }; - - let mut i = 0; - return scan_until_char(line, ':', &mut i) && - scan_char(line, ':', &mut i) && - scan_integer(line, &mut i) && - scan_char(line, ':', &mut i) && - scan_integer(line, &mut i) && - scan_char(line, ':', &mut i) && - scan_char(line, ' ', &mut i) && - scan_integer(line, &mut i) && - scan_char(line, ':', &mut i) && - scan_integer(line, &mut i) && - scan_char(line, ' ', &mut i) && - (scan_string(line, "error", &mut i) || - scan_string(line, "warning", &mut i) || - (expect_help && scan_string(line, "help", &mut i)) || - (expect_note && scan_string(line, "note", &mut i)) - ); -} - -fn scan_until_char(haystack: &str, needle: char, idx: &mut usize) -> bool { - if *idx >= haystack.len() { - return false; - } - let opt = haystack[(*idx)..].find(needle); - if opt.is_none() { - return false; - } - *idx = opt.unwrap(); - return true; -} - -fn scan_char(haystack: &str, needle: char, idx: &mut usize) -> bool { - if *idx >= haystack.len() { - return false; - } - let ch = haystack[*idx..].chars().next().unwrap(); - if ch != needle { - return false; - } - *idx += ch.len_utf8(); - return true; -} - -fn scan_integer(haystack: &str, idx: &mut usize) -> bool { - let mut i = *idx; - while i < haystack.len() { - let ch = haystack[i..].chars().next().unwrap(); - if ch < '0' || '9' < ch { - break; - } - i += ch.len_utf8(); - } - if i == *idx { - return false; + error(revision, + &format!("{} unexpected errors found, {} expected errors not found", + unexpected, not_found)); + print!("status: {}\ncommand: {}\n", + proc_res.status, proc_res.cmdline); + println!("actual errors (from JSON output): {:#?}\n", actual_errors); + println!("expected errors (from test file): {:#?}\n", expected_errors); + panic!(); } - *idx = i; - return true; } -fn scan_string(haystack: &str, needle: &str, idx: &mut usize) -> bool { - let mut haystack_i = *idx; - let mut needle_i = 0; - while needle_i < needle.len() { - if haystack_i >= haystack.len() { - return false; - } - let ch = haystack[haystack_i..].chars().next().unwrap(); - haystack_i += ch.len_utf8(); - if !scan_char(needle, ch, &mut needle_i) { - return false; - } +/// Returns true if we should report an error about `actual_error`, +/// which did not match any of the expected error. We always require +/// errors/warnings to be explicitly listed, but only require +/// helps/notes if there are explicit helps/notes given. +fn is_unexpected_compiler_message(actual_error: &Error, + expect_help: bool, + expect_note: bool) + -> bool { + match actual_error.kind { + Some(ErrorKind::Help) => expect_help, + Some(ErrorKind::Note) => expect_note, + Some(ErrorKind::Error) => true, + Some(ErrorKind::Warning) => true, + Some(ErrorKind::Suggestion) => false, + None => false } - *idx = haystack_i; - return true; } struct ProcArgs { @@ -1444,6 +1347,37 @@ fn make_compile_args(config: &Config, "-L".to_owned(), config.build_base.to_str().unwrap().to_owned(), format!("--target={}", target)); + + match config.mode { + CompileFail | + ParseFail | + Incremental => { + // If we are extracting and matching errors in the new + // fashion, then you want JSON mode. Old-skool error + // patterns still match the raw compiler output. + if props.error_patterns.is_empty() { + args.extend(["--error-format", + "json", + "-Z", + "unstable-options"] + .iter() + .map(|s| s.to_string())); + } + } + + RunFail | + RunPass | + RunPassValgrind | + Pretty | + DebugInfoGdb | + DebugInfoLldb | + Codegen | + Rustdoc | + CodegenUnits => { + // do not use JSON output + } + } + args.extend_from_slice(&extras); if !props.no_prefer_dynamic { args.push("-C".to_owned()); @@ -1901,7 +1835,7 @@ fn run_rustdoc_test(config: &Config, props: &TestProps, testpaths: &TestPaths) { let res = cmd2procres(config, testpaths, - Command::new(&config.python) + Command::new(&config.docck_python) .arg(root.join("src/etc/htmldocck.py")) .arg(out_dir) .arg(&testpaths.file)); diff --git a/src/tools/rustbook/main.rs b/src/tools/rustbook/main.rs index 5ad4982e8af6e..e0092f8e29e73 100644 --- a/src/tools/rustbook/main.rs +++ b/src/tools/rustbook/main.rs @@ -19,10 +19,8 @@ extern crate rustdoc; extern crate rustc_back; use std::env; -use std::error::Error; use std::process; use std::sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering}; -use subcommand::Subcommand; use term::Term; mod term; diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 84d3ff2b238bb..43475f203d57c 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -35,7 +35,7 @@ pub fn check(path: &Path, bad: &mut bool) { return } - let metadata = t!(fs::metadata(&file)); + let metadata = t!(fs::metadata(&file), &file); if metadata.mode() & 0o111 != 0 { println!("binary checked into source: {}", file.display()); *bad = true; diff --git a/src/tools/tidy/src/cargo.rs b/src/tools/tidy/src/cargo.rs index a170ecfdce096..77dcf9c1bd81f 100644 --- a/src/tools/tidy/src/cargo.rs +++ b/src/tools/tidy/src/cargo.rs @@ -20,7 +20,7 @@ use std::fs::File; use std::path::Path; pub fn check(path: &Path, bad: &mut bool) { - for entry in t!(path.read_dir()).map(|e| t!(e)) { + for entry in t!(path.read_dir(), path).map(|e| t!(e)) { // Look for `Cargo.toml` with a sibling `src/lib.rs` or `lib.rs` if entry.file_name().to_str() == Some("Cargo.toml") { if path.join("src/lib.rs").is_file() { diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 85b9c345e199c..e9e2508aba9bd 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -19,6 +19,11 @@ use std::path::{PathBuf, Path}; use std::env; macro_rules! t { + ($e:expr, $p:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed on {} with {}", stringify!($e), ($p).display(), e), + }); + ($e:expr) => (match $e { Ok(e) => e, Err(e) => panic!("{} failed with {}", stringify!($e), e), @@ -63,7 +68,7 @@ fn filter_dirs(path: &Path) -> bool { fn walk(path: &Path, skip: &mut FnMut(&Path) -> bool, f: &mut FnMut(&Path)) { - for entry in t!(fs::read_dir(path)) { + for entry in t!(fs::read_dir(path), path) { let entry = t!(entry); let kind = t!(entry.file_type()); let path = entry.path(); diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 4c5f72c1e7960..61230b3b030e5 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -52,7 +52,7 @@ pub fn check(path: &Path, bad: &mut bool) { } contents.truncate(0); - t!(t!(File::open(file)).read_to_string(&mut contents)); + t!(t!(File::open(file), file).read_to_string(&mut contents)); let skip_cr = contents.contains("ignore-tidy-cr"); let skip_tab = contents.contains("ignore-tidy-tab"); let skip_length = contents.contains("ignore-tidy-linelength");