about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-10-08 23:31:24 +0200
committerGitHub <noreply@github.com>2019-10-08 23:31:24 +0200
commitecd6229f72538216f27d27ef4710624e974b9e79 (patch)
treed05bafd2e4cb0da4e801ffbe84bc4ad1ca9c662a
parent9b989ea298dff9ba1091a54a25fcce51c529471d (diff)
parent7a8415894febab8eb0e796b26a87458aa9b54345 (diff)
downloadrust-ecd6229f72538216f27d27ef4710624e974b9e79.tar.gz
rust-ecd6229f72538216f27d27ef4710624e974b9e79.zip
Rollup merge of #65135 - GuillaumeGomez:add-error-code-check, r=Mark-Simulacrum
Add check for missing tests for error codes

Fixes #64811.

r? @Mark-Simulacrum
-rw-r--r--src/librustc/error_codes.rs18
-rw-r--r--src/librustc_lint/error_codes.rs2
-rw-r--r--src/librustc_mir/error_codes.rs2
-rw-r--r--src/librustc_passes/error_codes.rs25
-rw-r--r--src/librustc_privacy/error_codes.rs23
-rw-r--r--src/librustc_typeck/error_codes.rs32
-rw-r--r--src/tools/tidy/src/error_codes_check.rs137
-rw-r--r--src/tools/tidy/src/lib.rs1
-rw-r--r--src/tools/tidy/src/main.rs1
9 files changed, 205 insertions, 36 deletions
diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs
index 4cee132ecae..0c9760b3c0f 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.
 
@@ -1562,7 +1561,9 @@ fn transmute_lifetime<'a, T>(t: &'a (T,)) -> &'a T {
 "##,
 
 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> {
@@ -1594,8 +1595,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
@@ -2125,7 +2129,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
@@ -2165,10 +2169,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 ea2e1d9ecc5..2edc8fadf45 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 fb1311de9a7..77853ff1fe8 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 fbd06c34800..e460e9813b3 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 67066466f1d..03afb547d3a 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: 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 3a07171b12f..8bd899ae4d5 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<u32>),
     Baz,
@@ -1892,7 +1893,7 @@ This fails because `Vec<T>` 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<T, U> CoerceUnsized<MyType<U>> for MyType<T>
 [`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 {
     <MyStruct as Foo>::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 00000000000..159baff184d
--- /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<String, bool>) {
+    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<String, bool>) {
+    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<String, bool> = 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 337f9c4d6db..eb93eb29747 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 a57238ad814..e08c23c01fe 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");