diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index 66c51000066b2..b6b3514ff4c9d 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -466,7 +466,6 @@ fn main() { ``` "##, - E0139: r##" #### Note: this error code is no longer emitted by the compiler. @@ -1521,7 +1520,9 @@ where "##, E0496: r##" -A lifetime name is shadowing another lifetime name. Erroneous code example: +A lifetime name is shadowing another lifetime name. + +Erroneous code example: ```compile_fail,E0496 struct Foo<'a> { @@ -1553,8 +1554,11 @@ fn main() { "##, E0497: r##" -A stability attribute was used outside of the standard library. Erroneous code -example: +#### Note: this error code is no longer emitted by the compiler. + +A stability attribute was used outside of the standard library. + +Erroneous code example: ```compile_fail #[stable] // error: stability attributes may not be used outside of the @@ -2063,7 +2067,7 @@ rejected in your own crates. // E0272, // on_unimplemented #0 // E0273, // on_unimplemented #1 // E0274, // on_unimplemented #2 - E0278, // requirement is not satisfied +// E0278, // requirement is not satisfied E0279, // requirement is not satisfied E0280, // requirement is not satisfied // E0285, // overflow evaluation builtin bounds @@ -2106,10 +2110,10 @@ rejected in your own crates. E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders E0697, // closures cannot be static - E0707, // multiple elided lifetimes used in arguments of `async fn` +// E0707, // multiple elided lifetimes used in arguments of `async fn` E0708, // `async` non-`move` closures with parameters are not currently // supported - E0709, // multiple different lifetimes used in arguments of `async fn` +// E0709, // multiple different lifetimes used in arguments of `async fn` E0710, // an unknown tool name found in scoped lint E0711, // a feature has been declared with conflicting stability attributes // E0702, // replaced with a generic attribute input check diff --git a/src/librustc_lint/error_codes.rs b/src/librustc_lint/error_codes.rs index ea2e1d9ecc53f..2edc8fadf4568 100644 --- a/src/librustc_lint/error_codes.rs +++ b/src/librustc_lint/error_codes.rs @@ -1,4 +1,4 @@ syntax::register_diagnostics! { ; - E0721, // `await` keyword +// E0721, // `await` keyword } diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs index fb1311de9a706..77853ff1fe80a 100644 --- a/src/librustc_mir/error_codes.rs +++ b/src/librustc_mir/error_codes.rs @@ -953,7 +953,7 @@ https://doc.rust-lang.org/std/cell/ "##, E0388: r##" -E0388 was removed and is no longer issued. +#### Note: this error code is no longer emitted by the compiler. "##, E0389: r##" diff --git a/src/librustc_passes/error_codes.rs b/src/librustc_passes/error_codes.rs index 82cbcf458b074..0a21f56287da7 100644 --- a/src/librustc_passes/error_codes.rs +++ b/src/librustc_passes/error_codes.rs @@ -1,12 +1,15 @@ syntax::register_diagnostics! { -/* E0014: r##" +#### Note: this error code is no longer emitted by the compiler. + Constants can only be initialized by a constant value or, in a future version of Rust, a call to a const function. This error indicates the use of a path (like a::b, or x) denoting something other than one of these -allowed items. Erroneous code xample: +allowed items. -```compile_fail +Erroneous code example: + +``` const FOO: i32 = { let x = 0; x }; // 'x' isn't a constant nor a function! ``` @@ -18,10 +21,10 @@ const FOO: i32 = { const X : i32 = 0; X }; const FOO2: i32 = { 0 }; // but brackets are useless here ``` "##, -*/ E0130: r##" You declared a pattern as an argument in a foreign function declaration. + Erroneous code example: ```compile_fail @@ -57,6 +60,20 @@ extern { E0136: r##" A binary can only have one entry point, and by default that entry point is the function `main()`. If there are multiple such functions, please rename one. + +Erroneous code example: + +```compile_fail,E0136 +fn main() { + // ... +} + +// ... + +fn main() { // error! + // ... +} +``` "##, E0137: r##" diff --git a/src/librustc_privacy/error_codes.rs b/src/librustc_privacy/error_codes.rs index 67066466f1d22..03afb547d3a22 100644 --- a/src/librustc_privacy/error_codes.rs +++ b/src/librustc_privacy/error_codes.rs @@ -1,8 +1,9 @@ syntax::register_diagnostics! { E0445: r##" -A private trait was used on a public type parameter bound. Erroneous code -examples: +A private trait was used on a public type parameter bound. + +Erroneous code examples: ```compile_fail,E0445 #![deny(private_in_public)] @@ -32,7 +33,9 @@ pub fn foo (t: T) {} // ok! "##, E0446: r##" -A private type was used in a public type signature. Erroneous code example: +A private type was used in a public type signature. + +Erroneous code example: ```compile_fail,E0446 #![deny(private_in_public)] @@ -65,7 +68,9 @@ mod Foo { E0447: r##" #### Note: this error code is no longer emitted by the compiler. -The `pub` keyword was used inside a function. Erroneous code example: +The `pub` keyword was used inside a function. + +Erroneous code example: ``` fn foo() { @@ -79,7 +84,11 @@ is invalid. "##, E0448: r##" -The `pub` keyword was used inside a public enum. Erroneous code example: +#### Note: this error code is no longer emitted by the compiler. + +The `pub` keyword was used inside a public enum. + +Erroneous code example: ```compile_fail pub enum Foo { @@ -106,7 +115,9 @@ pub enum Foo { "##, E0451: r##" -A struct constructor with private fields was invoked. Erroneous code example: +A struct constructor with private fields was invoked. + +Erroneous code example: ```compile_fail,E0451 mod Bar { diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs index 3a07171b12fb8..8bd899ae4d5ce 100644 --- a/src/librustc_typeck/error_codes.rs +++ b/src/librustc_typeck/error_codes.rs @@ -1873,13 +1873,14 @@ This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this differs from the behavior for `&T`, which is always `Copy`). "##, -/* E0205: r##" +#### Note: this error code is no longer emitted by the compiler. + An attempt to implement the `Copy` trait for an enum failed because one of the variants does not implement `Copy`. To fix this, you must implement `Copy` for the mentioned variant. Note that this may not be possible, as in the example of -```compile_fail,E0205 +```compile_fail,E0204 enum Foo { Bar(Vec), Baz, @@ -1892,7 +1893,7 @@ This fails because `Vec` does not implement `Copy` for any `T`. Here's another example that will fail: -```compile_fail,E0205 +```compile_fail,E0204 #[derive(Copy)] enum Foo<'a> { Bar(&'a mut bool), @@ -1903,7 +1904,6 @@ enum Foo<'a> { This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this differs from the behavior for `&T`, which is always `Copy`). "##, -*/ E0206: r##" You can only implement `Copy` for a struct or enum. Both of the following @@ -2126,8 +2126,9 @@ For information on the design of the orphan rules, see [RFC 1023]. [RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md "##, -/* E0211: r##" +#### Note: this error code is no longer emitted by the compiler. + You used a function or type which doesn't fit the requirements for where it was used. Erroneous code examples: @@ -2174,7 +2175,7 @@ extern "rust-intrinsic" { } ``` -The second case example is a bit particular : the main function must always +The second case example is a bit particular: the main function must always have this definition: ```compile_fail @@ -2206,7 +2207,6 @@ impl Foo { } ``` "##, - */ E0220: r##" You used an associated type which isn't defined in the trait. @@ -2727,14 +2727,9 @@ impl CoerceUnsized> for MyType [`CoerceUnsized`]: https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html "##, -/* -// Associated consts can now be accessed through generic type parameters, and -// this error is no longer emitted. -// -// FIXME: consider whether to leave it in the error index, or remove it entirely -// as associated consts is not stabilized yet. - E0329: r##" +#### Note: this error code is no longer emitted by the compiler. + An attempt was made to access an associated constant through either a generic type parameter or `Self`. This is not supported yet. An example causing this error is shown below: @@ -2765,12 +2760,15 @@ trait Foo { struct MyStruct; +impl Foo for MyStruct { + const BAR: f64 = 0f64; +} + fn get_bar_good() -> f64 { ::BAR } ``` "##, -*/ E0366: r##" An attempt was made to implement `Drop` on a concrete specialization of a @@ -4973,7 +4971,7 @@ and the pin is required to keep it in the same place in memory. // between structures with the same definition // E0558, // replaced with a generic attribute input check // E0563, // cannot determine a type for this `impl Trait` removed in 6383de15 - E0564, // only named lifetimes are allowed in `impl Trait`, +// E0564, // only named lifetimes are allowed in `impl Trait`, // but `{}` was found in the type `{}` E0587, // type has conflicting packed and align representation hints E0588, // packed type cannot transitively contain a `[repr(align)]` type @@ -4986,7 +4984,7 @@ and the pin is required to keep it in the same place in memory. E0634, // type has conflicting packed representaton hints E0640, // infer outlives requirements E0641, // cannot cast to/from a pointer with an unknown kind - E0645, // trait aliases not finished +// E0645, // trait aliases not finished E0719, // duplicate values for associated type binding E0722, // Malformed `#[optimize]` attribute E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs new file mode 100644 index 0000000000000..159baff184d1b --- /dev/null +++ b/src/tools/tidy/src/error_codes_check.rs @@ -0,0 +1,137 @@ +//! Checks that all error codes have at least one test to prevent having error +//! codes that are silently not thrown by the compiler anymore. + +use std::collections::HashMap; +use std::ffi::OsStr; +use std::path::Path; + +// A few of those error codes can't be tested but all the others can and *should* be tested! +const WHITELIST: &[&str] = &[ + "E0183", + "E0227", + "E0279", + "E0280", + "E0311", + "E0313", + "E0314", + "E0315", + "E0377", + "E0456", + "E0461", + "E0462", + "E0464", + "E0465", + "E0472", + "E0473", + "E0474", + "E0475", + "E0476", + "E0479", + "E0480", + "E0481", + "E0482", + "E0483", + "E0484", + "E0485", + "E0486", + "E0487", + "E0488", + "E0489", + "E0514", + "E0519", + "E0523", + "E0526", + "E0554", + "E0570", + "E0629", + "E0630", + "E0640", + "E0717", + "E0727", + "E0729", +]; + +fn extract_error_codes(f: &str, error_codes: &mut HashMap) { + let mut reached_no_explanation = false; + let mut last_error_code = None; + + for line in f.lines() { + let s = line.trim(); + if s.starts_with('E') && s.ends_with(": r##\"") { + if let Some(err_code) = s.splitn(2, ':').next() { + let err_code = err_code.to_owned(); + last_error_code = Some(err_code.clone()); + if !error_codes.contains_key(&err_code) { + error_codes.insert(err_code, false); + } + } + } else if s.starts_with("```") && s.contains("compile_fail") && s.contains('E') { + if let Some(err_code) = s.splitn(2, 'E').skip(1).next() { + if let Some(err_code) = err_code.splitn(2, ',').next() { + let nb = error_codes.entry(format!("E{}", err_code)).or_insert(false); + *nb = true; + } + } + } else if s == ";" { + reached_no_explanation = true; + } else if reached_no_explanation && s.starts_with('E') { + if let Some(err_code) = s.splitn(2, ',').next() { + let err_code = err_code.to_owned(); + if !error_codes.contains_key(&err_code) { // this check should *never* fail! + error_codes.insert(err_code, false); + } + } + } else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") { + if let Some(last) = last_error_code { + error_codes.get_mut(&last).map(|x| *x = true); + } + last_error_code = None; + } + } +} + +fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap) { + for line in f.lines() { + let s = line.trim(); + if s.starts_with("error[E") || s.starts_with("warning[E") { + if let Some(err_code) = s.splitn(2, ']').next() { + if let Some(err_code) = err_code.splitn(2, '[').skip(1).next() { + let nb = error_codes.entry(err_code.to_owned()).or_insert(false); + *nb = true; + } + } + } + } +} + +pub fn check(path: &Path, bad: &mut bool) { + println!("Checking which error codes lack tests..."); + let mut error_codes: HashMap = HashMap::new(); + super::walk(path, + &mut |path| super::filter_dirs(path), + &mut |entry, contents| { + let file_name = entry.file_name(); + if file_name == "error_codes.rs" { + extract_error_codes(contents, &mut error_codes); + } else if entry.path().extension() == Some(OsStr::new("stderr")) { + extract_error_codes_from_tests(contents, &mut error_codes); + } + }); + println!("Found {} error codes", error_codes.len()); + + let mut errors = Vec::new(); + for (err_code, nb) in &error_codes { + if !*nb && !WHITELIST.contains(&err_code.as_str()) { + errors.push(format!("Error code {} needs to have at least one UI test!", err_code)); + } + } + errors.sort(); + for err in &errors { + eprintln!("{}", err); + } + println!("Found {} error codes with no tests", errors.len()); + if !errors.is_empty() { + *bad = true; + } + println!("Done!"); +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 337f9c4d6dbed..eb93eb297479d 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -41,6 +41,7 @@ pub mod extdeps; pub mod ui_tests; pub mod unit_tests; pub mod unstable_book; +pub mod error_codes_check; fn filter_dirs(path: &Path) -> bool { let skip = [ diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index a57238ad8148a..e08c23c01fe2d 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -35,6 +35,7 @@ fn main() { deps::check_whitelist(&path, &cargo, &mut bad); extdeps::check(&path, &mut bad); ui_tests::check(&path, &mut bad); + error_codes_check::check(&path, &mut bad); if bad { eprintln!("some tidy checks failed");