>) -> Option> {
- Some(panictry!(self.p.parse_expr()))
+ let r = panictry!(self.p.parse_expr());
+ if self.p.token != token::Eof {
+ self.p.sess.buffer_lint(
+ BufferedEarlyLintId::IncompleteInclude,
+ self.p.token.span,
+ ast::CRATE_NODE_ID,
+ "include macro expected single expression in source",
+ );
+ }
+ Some(r)
}
fn make_items(mut self: Box>) -> Option; 1]>> {
diff --git a/src/test/ui/if/if-no-match-bindings.stderr b/src/test/ui/if/if-no-match-bindings.stderr
index 53b7aafc430a2..0936f3b9e38e8 100644
--- a/src/test/ui/if/if-no-match-bindings.stderr
+++ b/src/test/ui/if/if-no-match-bindings.stderr
@@ -29,7 +29,7 @@ LL | if &true {}
| ^^^^^
| |
| expected bool, found &bool
- | help: consider dereferencing the borrow: `*&true`
+ | help: consider removing the borrow: `true`
|
= note: expected type `bool`
found type `&bool`
@@ -41,7 +41,7 @@ LL | if &mut true {}
| ^^^^^^^^^
| |
| expected bool, found &mut bool
- | help: consider dereferencing the borrow: `*&mut true`
+ | help: consider removing the borrow: `true`
|
= note: expected type `bool`
found type `&mut bool`
@@ -77,7 +77,7 @@ LL | while &true {}
| ^^^^^
| |
| expected bool, found &bool
- | help: consider dereferencing the borrow: `*&true`
+ | help: consider removing the borrow: `true`
|
= note: expected type `bool`
found type `&bool`
@@ -89,7 +89,7 @@ LL | while &mut true {}
| ^^^^^^^^^
| |
| expected bool, found &mut bool
- | help: consider dereferencing the borrow: `*&mut true`
+ | help: consider removing the borrow: `true`
|
= note: expected type `bool`
found type `&mut bool`
diff --git a/src/test/ui/include-single-expr-helper-1.rs b/src/test/ui/include-single-expr-helper-1.rs
new file mode 100644
index 0000000000000..aa6380bd24dc7
--- /dev/null
+++ b/src/test/ui/include-single-expr-helper-1.rs
@@ -0,0 +1,5 @@
+// ignore-test auxiliary file for include-single-expr.rs
+
+0
+
+// trailing comment permitted
diff --git a/src/test/ui/include-single-expr-helper.rs b/src/test/ui/include-single-expr-helper.rs
new file mode 100644
index 0000000000000..84d8b69603b6b
--- /dev/null
+++ b/src/test/ui/include-single-expr-helper.rs
@@ -0,0 +1,5 @@
+// ignore-test auxiliary file for include-single-expr.rs
+
+0
+10
+100
diff --git a/src/test/ui/include-single-expr.rs b/src/test/ui/include-single-expr.rs
new file mode 100644
index 0000000000000..0f4c29ec01456
--- /dev/null
+++ b/src/test/ui/include-single-expr.rs
@@ -0,0 +1,6 @@
+// error-pattern include macro expected single expression
+
+fn main() {
+ include!("include-single-expr-helper.rs");
+ include!("include-single-expr-helper-1.rs");
+}
diff --git a/src/test/ui/include-single-expr.stderr b/src/test/ui/include-single-expr.stderr
new file mode 100644
index 0000000000000..80eecf8f1b979
--- /dev/null
+++ b/src/test/ui/include-single-expr.stderr
@@ -0,0 +1,10 @@
+error: include macro expected single expression in source
+ --> $DIR/include-single-expr-helper.rs:4:1
+ |
+LL | 10
+ | ^^
+ |
+ = note: `#[deny(incomplete_include)]` on by default
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/inner-static-type-parameter.stderr b/src/test/ui/inner-static-type-parameter.stderr
index dfc663e4a79f8..1e74445af55cb 100644
--- a/src/test/ui/inner-static-type-parameter.stderr
+++ b/src/test/ui/inner-static-type-parameter.stderr
@@ -2,9 +2,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/inner-static-type-parameter.rs:6:19
|
LL | fn foo() {
- | --- - type parameter from outer function
- | |
- | try adding a local generic parameter in this method instead
+ | - type parameter from outer function
LL | static a: Bar = Bar::What;
| ^ use of generic parameter from outer function
diff --git a/src/test/ui/resolve/issue-65025-extern-static-parent-generics.rs b/src/test/ui/resolve/issue-65025-extern-static-parent-generics.rs
new file mode 100644
index 0000000000000..ce45f630e48a5
--- /dev/null
+++ b/src/test/ui/resolve/issue-65025-extern-static-parent-generics.rs
@@ -0,0 +1,10 @@
+unsafe fn foo() {
+ extern "C" {
+ static baz: *const A;
+ //~^ ERROR can't use generic parameters from outer function
+ }
+
+ let bar: *const u64 = core::mem::transmute(&baz);
+}
+
+fn main() { }
diff --git a/src/test/ui/resolve/issue-65025-extern-static-parent-generics.stderr b/src/test/ui/resolve/issue-65025-extern-static-parent-generics.stderr
new file mode 100644
index 0000000000000..6bbf76dd1fbb2
--- /dev/null
+++ b/src/test/ui/resolve/issue-65025-extern-static-parent-generics.stderr
@@ -0,0 +1,12 @@
+error[E0401]: can't use generic parameters from outer function
+ --> $DIR/issue-65025-extern-static-parent-generics.rs:3:28
+ |
+LL | unsafe fn foo() {
+ | - type parameter from outer function
+LL | extern "C" {
+LL | static baz: *const A;
+ | ^ use of generic parameter from outer function
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0401`.
diff --git a/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs b/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs
new file mode 100644
index 0000000000000..63d3431ec9b2f
--- /dev/null
+++ b/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs
@@ -0,0 +1,29 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+fn f() {
+ extern "C" {
+ static a: *const T;
+ //~^ ERROR can't use generic parameters from outer function
+ }
+}
+
+fn g() {
+ static a: *const T = Default::default();
+ //~^ ERROR can't use generic parameters from outer function
+}
+
+fn h() {
+ extern "C" {
+ static a: [u8; N];
+ //~^ ERROR can't use generic parameters from outer function
+ }
+}
+
+fn i() {
+ static a: [u8; N] = [0; N];
+ //~^ ERROR can't use generic parameters from outer function
+ //~^^ ERROR can't use generic parameters from outer function
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr
new file mode 100644
index 0000000000000..82e2aa2db8e25
--- /dev/null
+++ b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr
@@ -0,0 +1,53 @@
+error[E0401]: can't use generic parameters from outer function
+ --> $DIR/issue-65035-static-with-parent-generics.rs:6:26
+ |
+LL | fn f() {
+ | - type parameter from outer function
+LL | extern "C" {
+LL | static a: *const T;
+ | ^ use of generic parameter from outer function
+
+error[E0401]: can't use generic parameters from outer function
+ --> $DIR/issue-65035-static-with-parent-generics.rs:12:22
+ |
+LL | fn g() {
+ | - type parameter from outer function
+LL | static a: *const T = Default::default();
+ | ^ use of generic parameter from outer function
+
+error[E0401]: can't use generic parameters from outer function
+ --> $DIR/issue-65035-static-with-parent-generics.rs:18:24
+ |
+LL | fn h() {
+ | - const parameter from outer function
+LL | extern "C" {
+LL | static a: [u8; N];
+ | ^ use of generic parameter from outer function
+
+error[E0401]: can't use generic parameters from outer function
+ --> $DIR/issue-65035-static-with-parent-generics.rs:24:20
+ |
+LL | fn i() {
+ | - const parameter from outer function
+LL | static a: [u8; N] = [0; N];
+ | ^ use of generic parameter from outer function
+
+error[E0401]: can't use generic parameters from outer function
+ --> $DIR/issue-65035-static-with-parent-generics.rs:24:29
+ |
+LL | fn i() {
+ | - const parameter from outer function
+LL | static a: [u8; N] = [0; N];
+ | ^ use of generic parameter from outer function
+
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+ --> $DIR/issue-65035-static-with-parent-generics.rs:1:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0401`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index 619f9c85b24db..ad4686c1915d6 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -520,7 +520,7 @@ LL | if &let 0 = 0 {}
| ^^^^^^^^^^
| |
| expected bool, found &bool
- | help: consider dereferencing the borrow: `*&let 0 = 0`
+ | help: consider removing the borrow: `let 0 = 0`
|
= note: expected type `bool`
found type `&bool`
@@ -708,7 +708,7 @@ LL | while &let 0 = 0 {}
| ^^^^^^^^^^
| |
| expected bool, found &bool
- | help: consider dereferencing the borrow: `*&let 0 = 0`
+ | help: consider removing the borrow: `let 0 = 0`
|
= note: expected type `bool`
found type `&bool`
diff --git a/src/test/ui/suggestions/remove-as_str.stderr b/src/test/ui/suggestions/remove-as_str.stderr
index 2e8b72ebd4f6d..eae9cc075084a 100644
--- a/src/test/ui/suggestions/remove-as_str.stderr
+++ b/src/test/ui/suggestions/remove-as_str.stderr
@@ -2,25 +2,25 @@ error[E0599]: no method named `as_str` found for type `&str` in the current scop
--> $DIR/remove-as_str.rs:2:7
|
LL | s.as_str();
- | ^^^^^^ try removing `as_str`
+ | -^^^^^^-- help: remove this method call
error[E0599]: no method named `as_str` found for type `&'a str` in the current scope
--> $DIR/remove-as_str.rs:7:7
|
LL | s.as_str();
- | ^^^^^^ try removing `as_str`
+ | -^^^^^^-- help: remove this method call
error[E0599]: no method named `as_str` found for type `&mut str` in the current scope
--> $DIR/remove-as_str.rs:12:7
|
LL | s.as_str();
- | ^^^^^^ try removing `as_str`
+ | -^^^^^^-- help: remove this method call
error[E0599]: no method named `as_str` found for type `&&str` in the current scope
--> $DIR/remove-as_str.rs:17:7
|
LL | s.as_str();
- | ^^^^^^ try removing `as_str`
+ | -^^^^^^-- help: remove this method call
error: aborting due to 4 previous errors
diff --git a/src/tools/error_index_generator/build.rs b/src/tools/error_index_generator/build.rs
index 592b3f14c85af..c59533da1dc39 100644
--- a/src/tools/error_index_generator/build.rs
+++ b/src/tools/error_index_generator/build.rs
@@ -15,7 +15,7 @@ fn main() {
println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap());
let file = fs::read_to_string(entry.path()).unwrap()
.replace("syntax::register_diagnostics!", "register_diagnostics!");
- let contents = format!("(|| {{\n{}\n}})();", file);
+ let contents = format!("(|| {{\n{}\n}})()", file);
fs::write(&out_dir.join(&format!("error_{}.rs", idx)), &contents).unwrap();
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");