about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-04-22 23:19:20 +0200
committerGitHub <noreply@github.com>2020-04-22 23:19:20 +0200
commitd3e24bd457df2c707f0ac8e1943ea3872b1a8b73 (patch)
treeb47c60a729093d4a26013f4be7f4135bc8312185
parent10e47f5b7b58e1413ddc7cbb3164138c15e9684e (diff)
parent5cdea2d605f7a43a95935a6bce17176d32fdb51a (diff)
downloadrust-d3e24bd457df2c707f0ac8e1943ea3872b1a8b73.tar.gz
rust-d3e24bd457df2c707f0ac8e1943ea3872b1a8b73.zip
Rollup merge of #71350 - GuillaumeGomez:error-code-explanation-extra-check, r=oli-obk
Error code explanation extra check

r? @Mark-Simulacrum
-rw-r--r--src/librustc_error_codes/error_codes/E0060.md4
-rw-r--r--src/librustc_error_codes/error_codes/E0130.md2
-rw-r--r--src/librustc_error_codes/error_codes/E0198.md2
-rw-r--r--src/librustc_error_codes/error_codes/E0202.md10
-rw-r--r--src/librustc_error_codes/error_codes/E0230.md10
-rw-r--r--src/librustc_error_codes/error_codes/E0231.md10
-rw-r--r--src/librustc_error_codes/error_codes/E0232.md10
-rw-r--r--src/librustc_error_codes/error_codes/E0281.md2
-rw-r--r--src/librustc_error_codes/error_codes/E0364.md26
-rw-r--r--src/librustc_error_codes/error_codes/E0378.md2
-rw-r--r--src/librustc_error_codes/error_codes/E0590.md2
-rw-r--r--src/librustc_error_codes/error_codes/E0639.md12
-rw-r--r--src/librustc_error_codes/error_codes/E0644.md10
-rw-r--r--src/librustc_error_codes/error_codes/E0658.md2
-rw-r--r--src/librustc_error_codes/error_codes/E0669.md12
-rw-r--r--src/librustc_error_codes/error_codes/E0698.md2
-rw-r--r--src/librustc_error_codes/error_codes/E0700.md2
-rw-r--r--src/librustc_error_codes/error_codes/E0708.md2
-rw-r--r--src/librustc_error_codes/error_codes/E0714.md14
-rw-r--r--src/librustc_error_codes/error_codes/E0715.md19
-rw-r--r--src/librustc_error_codes/error_codes/E0727.md24
-rw-r--r--src/librustc_error_codes/error_codes/E0732.md21
-rw-r--r--src/librustc_error_codes/error_codes/E0740.md15
-rw-r--r--src/librustc_error_codes/error_codes/E0744.md11
-rw-r--r--src/tools/tidy/src/error_codes_check.rs89
25 files changed, 231 insertions, 84 deletions
diff --git a/src/librustc_error_codes/error_codes/E0060.md b/src/librustc_error_codes/error_codes/E0060.md
index 7a07b8e7ed6..e6906d72367 100644
--- a/src/librustc_error_codes/error_codes/E0060.md
+++ b/src/librustc_error_codes/error_codes/E0060.md
@@ -2,12 +2,14 @@ External C functions are allowed to be variadic. However, a variadic function
 takes a minimum number of arguments. For example, consider C's variadic `printf`
 function:
 
-```
+```compile_fail,E0060
 use std::os::raw::{c_char, c_int};
 
 extern "C" {
     fn printf(_: *const c_char, ...) -> c_int;
 }
+
+unsafe { printf(); } // error!
 ```
 
 Using this declaration, it must be called with at least one argument, so
diff --git a/src/librustc_error_codes/error_codes/E0130.md b/src/librustc_error_codes/error_codes/E0130.md
index 539049edb33..a270feaf58c 100644
--- a/src/librustc_error_codes/error_codes/E0130.md
+++ b/src/librustc_error_codes/error_codes/E0130.md
@@ -2,7 +2,7 @@ A pattern was declared as an argument in a foreign function declaration.
 
 Erroneous code example:
 
-```compile_fail
+```compile_fail,E0130
 extern {
     fn foo((a, b): (u32, u32)); // error: patterns aren't allowed in foreign
                                 //        function declarations
diff --git a/src/librustc_error_codes/error_codes/E0198.md b/src/librustc_error_codes/error_codes/E0198.md
index 687214a2050..90f1e542874 100644
--- a/src/librustc_error_codes/error_codes/E0198.md
+++ b/src/librustc_error_codes/error_codes/E0198.md
@@ -2,7 +2,7 @@ A negative implementation was marked as unsafe.
 
 Erroneous code example:
 
-```compile_fail
+```compile_fail,E0198
 struct Foo;
 
 unsafe impl !Clone for Foo { } // error!
diff --git a/src/librustc_error_codes/error_codes/E0202.md b/src/librustc_error_codes/error_codes/E0202.md
index b20d338c5fd..afc61ec2e48 100644
--- a/src/librustc_error_codes/error_codes/E0202.md
+++ b/src/librustc_error_codes/error_codes/E0202.md
@@ -1,5 +1,15 @@
 Inherent associated types were part of [RFC 195] but are not yet implemented.
 See [the tracking issue][iss8995] for the status of this implementation.
 
+Erroneous code example:
+
+```compile_fail,E0202
+struct Foo;
+
+impl Foo {
+    type Bar = isize; // error!
+}
+```
+
 [RFC 195]: https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md
 [iss8995]: https://github.com/rust-lang/rust/issues/8995
diff --git a/src/librustc_error_codes/error_codes/E0230.md b/src/librustc_error_codes/error_codes/E0230.md
index 9dbcb8e010b..cfb72e74319 100644
--- a/src/librustc_error_codes/error_codes/E0230.md
+++ b/src/librustc_error_codes/error_codes/E0230.md
@@ -3,15 +3,11 @@ message for when a particular trait isn't implemented on a type placed in a
 position that needs that trait. For example, when the following code is
 compiled:
 
-```compile_fail
+```compile_fail,E0230
 #![feature(rustc_attrs)]
 
-fn foo<T: Index<u8>>(x: T){}
-
-#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
-trait Index<Idx> { /* ... */ }
-
-foo(true); // `bool` does not implement `Index<u8>`
+#[rustc_on_unimplemented = "error on `{Self}` with params `<{A},{B}>`"] // error
+trait BadAnnotation<A> {}
 ```
 
 There will be an error about `bool` not implementing `Index<u8>`, followed by a
diff --git a/src/librustc_error_codes/error_codes/E0231.md b/src/librustc_error_codes/error_codes/E0231.md
index 4f80da54540..23a0a88ecdd 100644
--- a/src/librustc_error_codes/error_codes/E0231.md
+++ b/src/librustc_error_codes/error_codes/E0231.md
@@ -3,15 +3,11 @@ message for when a particular trait isn't implemented on a type placed in a
 position that needs that trait. For example, when the following code is
 compiled:
 
-```compile_fail
+```compile_fail,E0231
 #![feature(rustc_attrs)]
 
-fn foo<T: Index<u8>>(x: T){}
-
-#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
-trait Index<Idx> { /* ... */ }
-
-foo(true); // `bool` does not implement `Index<u8>`
+#[rustc_on_unimplemented = "error on `{Self}` with params `<{A},{}>`"] // error!
+trait BadAnnotation<A> {}
 ```
 
 there will be an error about `bool` not implementing `Index<u8>`, followed by a
diff --git a/src/librustc_error_codes/error_codes/E0232.md b/src/librustc_error_codes/error_codes/E0232.md
index 07a031488d0..b310caefa6e 100644
--- a/src/librustc_error_codes/error_codes/E0232.md
+++ b/src/librustc_error_codes/error_codes/E0232.md
@@ -3,15 +3,11 @@ message for when a particular trait isn't implemented on a type placed in a
 position that needs that trait. For example, when the following code is
 compiled:
 
-```compile_fail
+```compile_fail,E0232
 #![feature(rustc_attrs)]
 
-fn foo<T: Index<u8>>(x: T){}
-
-#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
-trait Index<Idx> { /* ... */ }
-
-foo(true); // `bool` does not implement `Index<u8>`
+#[rustc_on_unimplemented(lorem="")] // error!
+trait BadAnnotation {}
 ```
 
 there will be an error about `bool` not implementing `Index<u8>`, followed by a
diff --git a/src/librustc_error_codes/error_codes/E0281.md b/src/librustc_error_codes/error_codes/E0281.md
index 1a9796d2790..1d7904b67dd 100644
--- a/src/librustc_error_codes/error_codes/E0281.md
+++ b/src/librustc_error_codes/error_codes/E0281.md
@@ -4,7 +4,7 @@ You tried to supply a type which doesn't implement some trait in a location
 which expected that trait. This error typically occurs when working with
 `Fn`-based types. Erroneous code example:
 
-```compile-fail
+```compile_fail
 fn foo<F: Fn(usize)>(x: F) { }
 
 fn main() {
diff --git a/src/librustc_error_codes/error_codes/E0364.md b/src/librustc_error_codes/error_codes/E0364.md
index ec1fb911f3c..d01fb0c9c42 100644
--- a/src/librustc_error_codes/error_codes/E0364.md
+++ b/src/librustc_error_codes/error_codes/E0364.md
@@ -3,27 +3,27 @@ attempted to `pub use` a type or value that was not itself public.
 
 Erroneous code example:
 
-```compile_fail
-mod foo {
-    const X: u32 = 1;
-}
-
-pub use foo::X;
+```compile_fail,E0364
+mod a {
+    fn foo() {}
 
-fn main() {}
+    mod a {
+        pub use super::foo; // error!
+    }
+}
 ```
 
 The solution to this problem is to ensure that the items that you are
 re-exporting are themselves marked with `pub`:
 
 ```
-mod foo {
-    pub const X: u32 = 1;
-}
-
-pub use foo::X;
+mod a {
+    pub fn foo() {} // ok!
 
-fn main() {}
+    mod a {
+        pub use super::foo;
+    }
+}
 ```
 
 See the [Use Declarations][use-declarations] section of the reference for
diff --git a/src/librustc_error_codes/error_codes/E0378.md b/src/librustc_error_codes/error_codes/E0378.md
index 7f4374738de..c6fe997f3dc 100644
--- a/src/librustc_error_codes/error_codes/E0378.md
+++ b/src/librustc_error_codes/error_codes/E0378.md
@@ -3,7 +3,7 @@ or a newtype wrapper around a pointer.
 
 Erroneous code example:
 
-```compile-fail,E0378
+```compile_fail,E0378
 #![feature(dispatch_from_dyn)]
 use std::ops::DispatchFromDyn;
 
diff --git a/src/librustc_error_codes/error_codes/E0590.md b/src/librustc_error_codes/error_codes/E0590.md
index 8032e45903c..df7aa4f0a1e 100644
--- a/src/librustc_error_codes/error_codes/E0590.md
+++ b/src/librustc_error_codes/error_codes/E0590.md
@@ -3,7 +3,7 @@
 
 Example of erroneous code:
 
-```compile_fail
+```compile_fail,E0590
 while break {}
 ```
 
diff --git a/src/librustc_error_codes/error_codes/E0639.md b/src/librustc_error_codes/error_codes/E0639.md
index c2d9662337f..4646e37fb75 100644
--- a/src/librustc_error_codes/error_codes/E0639.md
+++ b/src/librustc_error_codes/error_codes/E0639.md
@@ -3,5 +3,17 @@ instantiated from outside of the defining crate as it has been marked
 as `non_exhaustive` and as such more fields/variants may be added in
 future that could cause adverse side effects for this code.
 
+Erroneous code example:
+
+```ignore (it only works cross-crate)
+#[non_exhaustive]
+pub struct NormalStruct {
+    pub first_field: u16,
+    pub second_field: u16,
+}
+
+let ns = NormalStruct { first_field: 640, second_field: 480 }; // error!
+```
+
 It is recommended that you look for a `new` function or equivalent in the
 crate's documentation.
diff --git a/src/librustc_error_codes/error_codes/E0644.md b/src/librustc_error_codes/error_codes/E0644.md
index 7a653bd2264..277643dfb1a 100644
--- a/src/librustc_error_codes/error_codes/E0644.md
+++ b/src/librustc_error_codes/error_codes/E0644.md
@@ -2,17 +2,17 @@ A closure or generator was constructed that references its own type.
 
 Erroneous example:
 
-```compile-fail,E0644
+```compile_fail,E0644
 fn fix<F>(f: &F)
   where F: Fn(&F)
 {
-  f(&f);
+    f(&f);
 }
 
 fn main() {
-  fix(&|y| {
-    // Here, when `x` is called, the parameter `y` is equal to `x`.
-  });
+    fix(&|y| {
+        // Here, when `x` is called, the parameter `y` is equal to `x`.
+    });
 }
 ```
 
diff --git a/src/librustc_error_codes/error_codes/E0658.md b/src/librustc_error_codes/error_codes/E0658.md
index 44a38cee23d..d821b9027f1 100644
--- a/src/librustc_error_codes/error_codes/E0658.md
+++ b/src/librustc_error_codes/error_codes/E0658.md
@@ -2,7 +2,7 @@ An unstable feature was used.
 
 Erroneous code example:
 
-```compile_fail,E658
+```compile_fail,E0658
 #[repr(u128)] // error: use of unstable library feature 'repr128'
 enum Foo {
     Bar(u64),
diff --git a/src/librustc_error_codes/error_codes/E0669.md b/src/librustc_error_codes/error_codes/E0669.md
index 39de01eebe8..f078c441b34 100644
--- a/src/librustc_error_codes/error_codes/E0669.md
+++ b/src/librustc_error_codes/error_codes/E0669.md
@@ -1,5 +1,17 @@
 Cannot convert inline assembly operand to a single LLVM value.
 
+Erroneous code example:
+
+```compile_fail,E0669
+#![feature(llvm_asm)]
+
+fn main() {
+    unsafe {
+        llvm_asm!("" :: "r"("")); // error!
+    }
+}
+```
+
 This error usually happens when trying to pass in a value to an input inline
 assembly operand that is actually a pair of values. In particular, this can
 happen when trying to pass in a slice, for instance a `&str`. In Rust, these
diff --git a/src/librustc_error_codes/error_codes/E0698.md b/src/librustc_error_codes/error_codes/E0698.md
index d0fcec39902..3ba992a8476 100644
--- a/src/librustc_error_codes/error_codes/E0698.md
+++ b/src/librustc_error_codes/error_codes/E0698.md
@@ -3,7 +3,7 @@ generator can be constructed.
 
 Erroneous code example:
 
-```edition2018,compile-fail,E0698
+```edition2018,compile_fail,E0698
 async fn bar<T>() -> () {}
 
 async fn foo() {
diff --git a/src/librustc_error_codes/error_codes/E0700.md b/src/librustc_error_codes/error_codes/E0700.md
index 41ac4d948c2..b1eb8b66ad6 100644
--- a/src/librustc_error_codes/error_codes/E0700.md
+++ b/src/librustc_error_codes/error_codes/E0700.md
@@ -3,7 +3,7 @@ appear within the `impl Trait` itself.
 
 Erroneous code example:
 
-```compile-fail,E0700
+```compile_fail,E0700
 use std::cell::Cell;
 
 trait Trait<'a> { }
diff --git a/src/librustc_error_codes/error_codes/E0708.md b/src/librustc_error_codes/error_codes/E0708.md
index a0f53e38b53..9287fc803d1 100644
--- a/src/librustc_error_codes/error_codes/E0708.md
+++ b/src/librustc_error_codes/error_codes/E0708.md
@@ -2,7 +2,7 @@
 
 Erroneous code example:
 
-```compile_fail,edition2018
+```compile_fail,edition2018,E0708
 #![feature(async_closure)]
 
 fn main() {
diff --git a/src/librustc_error_codes/error_codes/E0714.md b/src/librustc_error_codes/error_codes/E0714.md
index e8707f3e390..45d1cafa690 100644
--- a/src/librustc_error_codes/error_codes/E0714.md
+++ b/src/librustc_error_codes/error_codes/E0714.md
@@ -1,5 +1,19 @@
 A `#[marker]` trait contained an associated item.
 
+Erroneous code example:
+
+```compile_fail,E0714
+#![feature(marker_trait_attr)]
+#![feature(associated_type_defaults)]
+
+#[marker]
+trait MarkerConst {
+    const N: usize; // error!
+}
+
+fn main() {}
+```
+
 The items of marker traits cannot be overridden, so there's no need to have them
 when they cannot be changed per-type anyway.  If you wanted them for ergonomic
 reasons, consider making an extension trait instead.
diff --git a/src/librustc_error_codes/error_codes/E0715.md b/src/librustc_error_codes/error_codes/E0715.md
index 9e20e813683..8f0022d9425 100644
--- a/src/librustc_error_codes/error_codes/E0715.md
+++ b/src/librustc_error_codes/error_codes/E0715.md
@@ -1,5 +1,24 @@
 An `impl` for a `#[marker]` trait tried to override an associated item.
 
+Erroneous code example:
+
+```compile_fail,E0715
+#![feature(marker_trait_attr)]
+
+#[marker]
+trait Marker {
+    const N: usize = 0;
+    fn do_something() {}
+}
+
+struct OverrideConst;
+impl Marker for OverrideConst { // error!
+    const N: usize = 1;
+}
+
+fn main() {}
+```
+
 Because marker traits are allowed to have multiple implementations for the same
 type, it's not allowed to override anything in those implementations, as it
 would be ambiguous which override should actually be used.
diff --git a/src/librustc_error_codes/error_codes/E0727.md b/src/librustc_error_codes/error_codes/E0727.md
index 528807ee9af..be1b68e645d 100644
--- a/src/librustc_error_codes/error_codes/E0727.md
+++ b/src/librustc_error_codes/error_codes/E0727.md
@@ -2,14 +2,16 @@ A `yield` clause was used in an `async` context.
 
 Example of erroneous code:
 
-```compile_fail
+```compile_fail,E0727,edition2018
 #![feature(generators)]
 
-let generator = || {
-    async {
-        yield;
-    }
-};
+fn main() {
+    let generator = || {
+        async {
+            yield;
+        }
+    };
+}
 ```
 
 Here, the `yield` keyword is used in an `async` block,
@@ -17,10 +19,12 @@ which is not yet supported.
 
 To fix this error, you have to move `yield` out of the `async` block:
 
-```
+```edition2018
 #![feature(generators)]
 
-let generator = || {
-    yield;
-};
+fn main() {
+    let generator = || {
+        yield;
+    };
+}
 ```
diff --git a/src/librustc_error_codes/error_codes/E0732.md b/src/librustc_error_codes/error_codes/E0732.md
index 03137590e88..7347e6654c5 100644
--- a/src/librustc_error_codes/error_codes/E0732.md
+++ b/src/librustc_error_codes/error_codes/E0732.md
@@ -1,5 +1,18 @@
 An `enum` with a discriminant must specify a `#[repr(inttype)]`.
 
+Erroneous code example:
+
+```compile_fail,E0732
+#![feature(arbitrary_enum_discriminant)]
+
+enum Enum { // error!
+    Unit = 1,
+    Tuple() = 2,
+    Struct{} = 3,
+}
+# fn main() {}
+```
+
 A `#[repr(inttype)]` must be provided on an `enum` if it has a non-unit
 variant with a discriminant, or where there are both unit variants with
 discriminants and non-unit variants. This restriction ensures that there
@@ -23,7 +36,9 @@ fn discriminant(v : &Enum) -> u8 {
     unsafe { *(v as *const Enum as *const u8) }
 }
 
-assert_eq!(3, discriminant(&Enum::Unit));
-assert_eq!(2, discriminant(&Enum::Tuple(5)));
-assert_eq!(1, discriminant(&Enum::Struct{a: 7, b: 11}));
+fn main() {
+    assert_eq!(3, discriminant(&Enum::Unit));
+    assert_eq!(2, discriminant(&Enum::Tuple(5)));
+    assert_eq!(1, discriminant(&Enum::Struct{a: 7, b: 11}));
+}
 ```
diff --git a/src/librustc_error_codes/error_codes/E0740.md b/src/librustc_error_codes/error_codes/E0740.md
index a9eb5f2790d..37776785189 100644
--- a/src/librustc_error_codes/error_codes/E0740.md
+++ b/src/librustc_error_codes/error_codes/E0740.md
@@ -1 +1,16 @@
 A `union` cannot have fields with destructors.
+
+Erroneous code example:
+
+```compile_fail,E0740
+union Test {
+    a: A, // error!
+}
+
+#[derive(Debug)]
+struct A(i32);
+
+impl Drop for A {
+    fn drop(&mut self) { println!("A"); }
+}
+```
diff --git a/src/librustc_error_codes/error_codes/E0744.md b/src/librustc_error_codes/error_codes/E0744.md
index 602fbc50a71..56b947a8282 100644
--- a/src/librustc_error_codes/error_codes/E0744.md
+++ b/src/librustc_error_codes/error_codes/E0744.md
@@ -3,16 +3,13 @@ Control-flow expressions are not allowed inside a const context.
 At the moment, `if` and `match`, as well as the looping constructs `for`,
 `while`, and `loop`, are forbidden inside a `const`, `static`, or `const fn`.
 
-```compile_fail,E0658
+```compile_fail,E0744
 const _: i32 = {
     let mut x = 0;
-    loop {
-        x += 1;
-        if x == 4 {
-            break;
-        }
+
+    for i in 0..4 { // error!
+        x += i;
     }
-    x
 };
 ```
 
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
index 428c57d3ee8..243d41598f8 100644
--- a/src/tools/tidy/src/error_codes_check.rs
+++ b/src/tools/tidy/src/error_codes_check.rs
@@ -15,21 +15,57 @@ const WHITELIST: &[&str] = &[
     "E0727", "E0729",
 ];
 
+// Some error codes don't have any tests apparently...
+const IGNORE_EXPLANATION_CHECK: &[&str] =
+    &["E0570", "E0601", "E0602", "E0639", "E0729", "E0749", "E0750", "E0751"];
+
 fn check_error_code_explanation(
     f: &str,
     error_codes: &mut HashMap<String, bool>,
     err_code: String,
-) {
+) -> bool {
+    let mut invalid_compile_fail_format = false;
+    let mut found_error_code = false;
+
     for line in f.lines() {
         let s = line.trim();
-        if s.starts_with("```") && s.contains("compile_fail") && s.contains('E') {
-            error_codes.insert(err_code, true);
-            return;
+        if s.starts_with("```") {
+            if s.contains("compile_fail") && s.contains('E') {
+                if !found_error_code {
+                    error_codes.insert(err_code.clone(), true);
+                    found_error_code = true;
+                }
+            } else if s.contains("compile-fail") {
+                invalid_compile_fail_format = true;
+            }
         } else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
-            error_codes.get_mut(&err_code).map(|x| *x = true);
-            return;
+            if !found_error_code {
+                error_codes.get_mut(&err_code).map(|x| *x = true);
+                found_error_code = true;
+            }
         }
     }
+    invalid_compile_fail_format
+}
+
+fn check_if_error_code_is_test_in_explanation(f: &str, err_code: &String) -> bool {
+    let mut can_be_ignored = false;
+
+    for line in f.lines() {
+        let s = line.trim();
+        if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
+            return true;
+        }
+        if s.starts_with("```") {
+            if s.contains("compile_fail") && s.contains(err_code) {
+                return true;
+            } else if s.contains("(") {
+                // It's very likely that we can't actually make it fail compilation...
+                can_be_ignored = true;
+            }
+        }
+    }
+    can_be_ignored
 }
 
 macro_rules! some_or_continue {
@@ -41,7 +77,12 @@ macro_rules! some_or_continue {
     };
 }
 
-fn extract_error_codes(f: &str, error_codes: &mut HashMap<String, bool>, path: &Path) {
+fn extract_error_codes(
+    f: &str,
+    error_codes: &mut HashMap<String, bool>,
+    path: &Path,
+    errors: &mut Vec<String>,
+) {
     let mut reached_no_explanation = false;
 
     for line in f.lines() {
@@ -55,10 +96,26 @@ fn extract_error_codes(f: &str, error_codes: &mut HashMap<String, bool>, path: &
                 // Now we extract the tests from the markdown file!
                 let md = some_or_continue!(s.splitn(2, "include_str!(\"").nth(1));
                 let md_file_name = some_or_continue!(md.splitn(2, "\")").next());
-                let path = some_or_continue!(path.parent()).join(md_file_name);
+                let path = some_or_continue!(path.parent())
+                    .join(md_file_name)
+                    .canonicalize()
+                    .expect("failed to canonicalize error explanation file path");
                 match read_to_string(&path) {
                     Ok(content) => {
-                        check_error_code_explanation(&content, error_codes, err_code);
+                        if !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str())
+                            && !check_if_error_code_is_test_in_explanation(&content, &err_code)
+                        {
+                            errors.push(format!(
+                                "`{}` doesn't use its own error code in compile_fail example",
+                                path.display(),
+                            ));
+                        }
+                        if check_error_code_explanation(&content, error_codes, err_code) {
+                            errors.push(format!(
+                                "`{}` uses invalid tag `compile-fail` instead of `compile_fail`",
+                                path.display(),
+                            ));
+                        }
                     }
                     Err(e) => {
                         eprintln!("Couldn't read `{}`: {}", path.display(), e);
@@ -94,22 +151,24 @@ fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap<String, boo
 }
 
 pub fn check(path: &Path, bad: &mut bool) {
+    let mut errors = Vec::new();
     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, entry.path());
+            extract_error_codes(contents, &mut error_codes, entry.path(), &mut errors);
         } 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());
+    if errors.is_empty() {
+        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));
+        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();