diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index a169736d85310..adf23a5cf2c85 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1934,20 +1934,52 @@ impl EarlyLintPass for KeywordIdents { self.check_tokens(cx, mac.node.tts.clone().into()); } fn check_ident(&mut self, cx: &EarlyContext, ident: ast::Ident) { - let next_edition = match cx.sess.edition() { + let ident_str = &ident.as_str()[..]; + let cur_edition = cx.sess.edition(); + let is_raw_ident = |ident: ast::Ident| { + cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) + }; + let next_edition = match cur_edition { Edition::Edition2015 => { - match &ident.as_str()[..] { + match ident_str { "async" | "try" | "dyn" => Edition::Edition2018, + // Only issue warnings for `await` if the `async_await` + // feature isn't being used. Otherwise, users need + // to keep using `await` for the macro exposed by std. + "await" if !cx.sess.features_untracked().async_await => Edition::Edition2018, _ => return, } } // no new keywords yet for 2018 edition and beyond - _ => return, + // However, `await` is a "false" keyword in the 2018 edition, + // and can only be used if the `async_await` feature is enabled. + // Otherwise, we emit an error. + _ => { + if "await" == ident_str + && !cx.sess.features_untracked().async_await + && !is_raw_ident(ident) + { + let mut err = struct_span_err!( + cx.sess, + ident.span, + E0721, + "`await` is a keyword in the {} edition", cur_edition, + ); + err.span_suggestion_with_applicability( + ident.span, + "you can use a raw identifier to stay compatible", + "r#await".to_string(), + Applicability::MachineApplicable, + ); + err.emit(); + } + return + }, }; // don't lint `r#foo` - if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) { + if is_raw_ident(ident) { return; } diff --git a/src/librustc_lint/diagnostics.rs b/src/librustc_lint/diagnostics.rs new file mode 100644 index 0000000000000..59f005a5de8da --- /dev/null +++ b/src/librustc_lint/diagnostics.rs @@ -0,0 +1,13 @@ +// Copyright 2018 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. + +register_diagnostics! { + E0721, // `await` keyword +} diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 9ed69a2dc9b8e..9e2e3435bd9b5 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -32,6 +32,7 @@ #![feature(rustc_diagnostic_macros)] #![feature(macro_at_most_once_rep)] +#[macro_use] extern crate syntax; #[macro_use] extern crate rustc; @@ -61,6 +62,7 @@ use syntax::edition::Edition; use lint::LintId; use lint::FutureIncompatibleInfo; +mod diagnostics; mod nonstandard_style; pub mod builtin; mod types; diff --git a/src/test/ui/await-keyword/2015-edition-no-warnings-with-feature-gate.rs b/src/test/ui/await-keyword/2015-edition-no-warnings-with-feature-gate.rs new file mode 100644 index 0000000000000..92c60e7d6eed0 --- /dev/null +++ b/src/test/ui/await-keyword/2015-edition-no-warnings-with-feature-gate.rs @@ -0,0 +1,16 @@ +// compile-pass + +#![feature(async_await)] +#![allow(non_camel_case_types)] +#![deny(keyword_idents)] + +mod outer_mod { + pub mod await { + pub struct await; + } +} +use outer_mod::await::await; + +fn main() { + match await { await => {} } +} diff --git a/src/test/ui/await-keyword/2015-edition-warning.fixed b/src/test/ui/await-keyword/2015-edition-warning.fixed new file mode 100644 index 0000000000000..c2c40cd11a63b --- /dev/null +++ b/src/test/ui/await-keyword/2015-edition-warning.fixed @@ -0,0 +1,15 @@ +// run-rustfix + +#![allow(non_camel_case_types)] +#![deny(keyword_idents)] + +mod outer_mod { + pub mod r#await { + pub struct r#await; + } +} +use outer_mod::r#await::r#await; + +fn main() { + match r#await { r#await => {} } +} diff --git a/src/test/ui/await-keyword/2015-edition-warning.rs b/src/test/ui/await-keyword/2015-edition-warning.rs new file mode 100644 index 0000000000000..95539ab29dc50 --- /dev/null +++ b/src/test/ui/await-keyword/2015-edition-warning.rs @@ -0,0 +1,15 @@ +// run-rustfix + +#![allow(non_camel_case_types)] +#![deny(keyword_idents)] + +mod outer_mod { + pub mod await { + pub struct await; + } +} +use outer_mod::await::await; + +fn main() { + match await { await => {} } +} diff --git a/src/test/ui/await-keyword/2015-edition-warning.stderr b/src/test/ui/await-keyword/2015-edition-warning.stderr new file mode 100644 index 0000000000000..073e9d7e6d009 --- /dev/null +++ b/src/test/ui/await-keyword/2015-edition-warning.stderr @@ -0,0 +1,61 @@ +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-warning.rs:7:13 + | +LL | pub mod await { + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | +note: lint level defined here + --> $DIR/2015-edition-warning.rs:4:9 + | +LL | #![deny(keyword_idents)] + | ^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-warning.rs:8:20 + | +LL | pub struct await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-warning.rs:11:16 + | +LL | use outer_mod::await::await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-warning.rs:11:23 + | +LL | use outer_mod::await::await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-warning.rs:14:11 + | +LL | match await { await => {} } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-warning.rs:14:19 + | +LL | match await { await => {} } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/await-keyword/2018-edition-error.rs b/src/test/ui/await-keyword/2018-edition-error.rs new file mode 100644 index 0000000000000..a9e2e3f79ee76 --- /dev/null +++ b/src/test/ui/await-keyword/2018-edition-error.rs @@ -0,0 +1,13 @@ +// edition:2018 +#![allow(non_camel_case_types)] + +mod outer_mod { + pub mod await { + pub struct await; + } +} +use self::outer_mod::await::await; + +fn main() { + match await { await => () } +} diff --git a/src/test/ui/await-keyword/2018-edition-error.stderr b/src/test/ui/await-keyword/2018-edition-error.stderr new file mode 100644 index 0000000000000..d5727b8db3790 --- /dev/null +++ b/src/test/ui/await-keyword/2018-edition-error.stderr @@ -0,0 +1,39 @@ +error[E0721]: `await` is a keyword in the 2018 edition + --> $DIR/2018-edition-error.rs:5:13 + | +LL | pub mod await { + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + +error[E0721]: `await` is a keyword in the 2018 edition + --> $DIR/2018-edition-error.rs:6:20 + | +LL | pub struct await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + +error[E0721]: `await` is a keyword in the 2018 edition + --> $DIR/2018-edition-error.rs:9:22 + | +LL | use self::outer_mod::await::await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + +error[E0721]: `await` is a keyword in the 2018 edition + --> $DIR/2018-edition-error.rs:9:29 + | +LL | use self::outer_mod::await::await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + +error[E0721]: `await` is a keyword in the 2018 edition + --> $DIR/2018-edition-error.rs:12:11 + | +LL | match await { await => () } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + +error[E0721]: `await` is a keyword in the 2018 edition + --> $DIR/2018-edition-error.rs:12:19 + | +LL | match await { await => () } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0721`. diff --git a/src/test/ui/await-keyword/2018-edition-no-error-with-feature-gate.rs b/src/test/ui/await-keyword/2018-edition-no-error-with-feature-gate.rs new file mode 100644 index 0000000000000..52d32c8351080 --- /dev/null +++ b/src/test/ui/await-keyword/2018-edition-no-error-with-feature-gate.rs @@ -0,0 +1,16 @@ +// compile-pass +// edition:2018 + +#![allow(non_camel_case_types)] +#![feature(async_await)] + +mod outer_mod { + pub mod await { + pub struct await; + } +} +use self::outer_mod::await::await; + +fn main() { + match await { await => () } +} diff --git a/src/test/ui/await-keyword/post_expansion_error.rs b/src/test/ui/await-keyword/post_expansion_error.rs new file mode 100644 index 0000000000000..580ca3b3a4f6c --- /dev/null +++ b/src/test/ui/await-keyword/post_expansion_error.rs @@ -0,0 +1,9 @@ +// edition:2018 + +macro_rules! r#await { + () => { println!("Hello, world!") } +} + +fn main() { + await!() +} diff --git a/src/test/ui/await-keyword/post_expansion_error.stderr b/src/test/ui/await-keyword/post_expansion_error.stderr new file mode 100644 index 0000000000000..76ae35b7517e3 --- /dev/null +++ b/src/test/ui/await-keyword/post_expansion_error.stderr @@ -0,0 +1,9 @@ +error[E0721]: `await` is a keyword in the 2018 edition + --> $DIR/post_expansion_error.rs:8:5 + | +LL | await!() + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0721`.