From 003cab25d7619f1eabb7de01ce6fa1ff3226b511 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 24 Aug 2018 13:48:20 -0700 Subject: [PATCH] Generalize `async_idents` to all new keywords This commit generalizes the existing `async_idents` lint to easily encompass other identifiers that will be keywords in future editions. The new lint is called `keyword_idents` and the old `async_idents` lint is registered as renamed to this new lint. As a proof of concept the `try` keyword was added to this list as it looks to be listed as a keyword in the 2018 edition only. The `await` keyword was not added as it's not listed as a keyword yet. Closes #53077 --- src/librustc/lint/context.rs | 2 +- src/librustc_lint/builtin.rs | 79 +++++++++++-------- src/librustc_lint/lib.rs | 5 +- .../auxiliary/edition-kw-macro-2015.rs | 2 +- .../auxiliary/edition-kw-macro-2018.rs | 2 +- .../edition-keywords-2015-2015-expansion.rs | 2 +- .../edition-keywords-2018-2015-expansion.rs | 2 +- .../ui/rust-2018/async-ident-allowed.stderr | 2 +- src/test/ui/rust-2018/async-ident.fixed | 2 +- src/test/ui/rust-2018/async-ident.rs | 2 +- src/test/ui/rust-2018/async-ident.stderr | 4 +- src/test/ui/rust-2018/try-ident.fixed | 21 +++++ src/test/ui/rust-2018/try-ident.rs | 21 +++++ src/test/ui/rust-2018/try-ident.stderr | 24 ++++++ 14 files changed, 125 insertions(+), 45 deletions(-) create mode 100644 src/test/ui/rust-2018/try-ident.fixed create mode 100644 src/test/ui/rust-2018/try-ident.rs create mode 100644 src/test/ui/rust-2018/try-ident.stderr diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 315ed38ad07..5cc862a58d3 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1046,7 +1046,7 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { self.check_id(id); } - fn visit_mac(&mut self, mac: &'ast ast::Mac) { + fn visit_mac(&mut self, mac: &'a ast::Mac) { run_lints!(self, check_mac, mac); } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c497627415f..16aa80c34cc 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -46,6 +46,7 @@ use syntax::tokenstream::{TokenTree, TokenStream}; use syntax::ast; use syntax::attr; use syntax::source_map::Spanned; +use syntax::edition::Edition; use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_attributes}; use syntax_pos::{BytePos, Span, SyntaxContext}; use syntax::symbol::keywords; @@ -1876,30 +1877,33 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestFunctions { } declare_lint! { - pub ASYNC_IDENTS, + pub KEYWORD_IDENTS, Allow, - "detects `async` being used as an identifier" + "detects edition keywords being used as an identifier" } -/// Checks for uses of `async` as an identifier +/// Checks for uses of edtion keywords used as an identifier #[derive(Clone)] -pub struct Async2018; +pub struct KeywordIdents; -impl LintPass for Async2018 { +impl LintPass for KeywordIdents { fn get_lints(&self) -> LintArray { - lint_array!(ASYNC_IDENTS) + lint_array!(KEYWORD_IDENTS) } } -impl Async2018 { +impl KeywordIdents { fn check_tokens(&mut self, cx: &EarlyContext, tokens: TokenStream) { for tt in tokens.into_trees() { match tt { TokenTree::Token(span, tok) => match tok.ident() { // only report non-raw idents - Some((ident, false)) if ident.as_str() == "async" => { - self.report(cx, span.substitute_dummy(ident.span)) - }, + Some((ident, false)) => { + self.check_ident(cx, ast::Ident { + span: span.substitute_dummy(ident.span), + ..ident + }); + } _ => {}, } TokenTree::Delimited(_, ref delim) => { @@ -1908,29 +1912,9 @@ impl Async2018 { } } } - fn report(&mut self, cx: &EarlyContext, span: Span) { - // don't lint `r#async` - if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&span) { - return; - } - let mut lint = cx.struct_span_lint( - ASYNC_IDENTS, - span, - "`async` is a keyword in the 2018 edition", - ); - - // Don't suggest about raw identifiers if the feature isn't active - lint.span_suggestion_with_applicability( - span, - "you can use a raw identifier to stay compatible", - "r#async".to_string(), - Applicability::MachineApplicable, - ); - lint.emit() - } } -impl EarlyLintPass for Async2018 { +impl EarlyLintPass for KeywordIdents { fn check_mac_def(&mut self, cx: &EarlyContext, mac_def: &ast::MacroDef, _id: ast::NodeId) { self.check_tokens(cx, mac_def.stream()); } @@ -1938,8 +1922,37 @@ impl EarlyLintPass for Async2018 { self.check_tokens(cx, mac.node.tts.clone().into()); } fn check_ident(&mut self, cx: &EarlyContext, ident: ast::Ident) { - if ident.as_str() == "async" { - self.report(cx, ident.span); + let next_edition = match cx.sess.edition() { + Edition::Edition2015 => { + match &ident.as_str()[..] { + "async" | + "try" => Edition::Edition2018, + _ => return, + } + } + + // no new keywords yet for 2018 edition and beyond + _ => return, + }; + + // don't lint `r#foo` + if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) { + return; } + + let mut lint = cx.struct_span_lint( + KEYWORD_IDENTS, + ident.span, + &format!("`{}` is a keyword in the {} edition", + ident.as_str(), + next_edition), + ); + lint.span_suggestion_with_applicability( + ident.span, + "you can use a raw identifier to stay compatible", + format!("r#{}", ident.as_str()), + Applicability::MachineApplicable, + ); + lint.emit() } } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 05b11e3ba3a..39abfee5fb9 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -110,7 +110,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { } add_pre_expansion_builtin!(sess, - Async2018, + KeywordIdents, ); add_early_builtin!(sess, @@ -240,7 +240,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { edition: Some(Edition::Edition2018), }, FutureIncompatibleInfo { - id: LintId::of(ASYNC_IDENTS), + id: LintId::of(KEYWORD_IDENTS), reference: "issue #49716 ", edition: Some(Edition::Edition2018), }, @@ -349,6 +349,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { store.register_renamed("bare_trait_object", "bare_trait_objects"); store.register_renamed("unstable_name_collision", "unstable_name_collisions"); store.register_renamed("unused_doc_comment", "unused_doc_comments"); + store.register_renamed("async_idents", "keyword_idents"); store.register_removed("unknown_features", "replaced by an error"); store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate"); store.register_removed("negate_unsigned", "cast a signed value instead"); diff --git a/src/test/ui/editions/auxiliary/edition-kw-macro-2015.rs b/src/test/ui/editions/auxiliary/edition-kw-macro-2015.rs index 5b8832ddaf2..9343312fdd8 100644 --- a/src/test/ui/editions/auxiliary/edition-kw-macro-2015.rs +++ b/src/test/ui/editions/auxiliary/edition-kw-macro-2015.rs @@ -10,7 +10,7 @@ // edition:2015 -#![allow(async_idents)] +#![allow(keyword_idents)] #[macro_export] macro_rules! produces_async { diff --git a/src/test/ui/editions/auxiliary/edition-kw-macro-2018.rs b/src/test/ui/editions/auxiliary/edition-kw-macro-2018.rs index 85ef15858fe..19a7b91624f 100644 --- a/src/test/ui/editions/auxiliary/edition-kw-macro-2018.rs +++ b/src/test/ui/editions/auxiliary/edition-kw-macro-2018.rs @@ -10,7 +10,7 @@ // edition:2018 -#![allow(async_idents)] +#![allow(keyword_idents)] #[macro_export] macro_rules! produces_async { diff --git a/src/test/ui/editions/edition-keywords-2015-2015-expansion.rs b/src/test/ui/editions/edition-keywords-2015-2015-expansion.rs index a9037a50ecb..382c7c1f325 100644 --- a/src/test/ui/editions/edition-keywords-2015-2015-expansion.rs +++ b/src/test/ui/editions/edition-keywords-2015-2015-expansion.rs @@ -12,7 +12,7 @@ // aux-build:edition-kw-macro-2015.rs // compile-pass -#![allow(async_idents)] +#![allow(keyword_idents)] #[macro_use] extern crate edition_kw_macro_2015; diff --git a/src/test/ui/editions/edition-keywords-2018-2015-expansion.rs b/src/test/ui/editions/edition-keywords-2018-2015-expansion.rs index 911dcd855aa..46434daaab9 100644 --- a/src/test/ui/editions/edition-keywords-2018-2015-expansion.rs +++ b/src/test/ui/editions/edition-keywords-2018-2015-expansion.rs @@ -12,7 +12,7 @@ // aux-build:edition-kw-macro-2015.rs // compile-pass -#![allow(async_idents)] +#![allow(keyword_idents)] #[macro_use] extern crate edition_kw_macro_2015; diff --git a/src/test/ui/rust-2018/async-ident-allowed.stderr b/src/test/ui/rust-2018/async-ident-allowed.stderr index 741c1c70209..68d7930e043 100644 --- a/src/test/ui/rust-2018/async-ident-allowed.stderr +++ b/src/test/ui/rust-2018/async-ident-allowed.stderr @@ -9,7 +9,7 @@ note: lint level defined here | LL | #![deny(rust_2018_compatibility)] | ^^^^^^^^^^^^^^^^^^^^^^^ - = note: #[deny(async_idents)] implied by #[deny(rust_2018_compatibility)] + = note: #[deny(keyword_idents)] implied by #[deny(rust_2018_compatibility)] = 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 diff --git a/src/test/ui/rust-2018/async-ident.fixed b/src/test/ui/rust-2018/async-ident.fixed index 15b8eec3bea..ef88f835fc8 100644 --- a/src/test/ui/rust-2018/async-ident.fixed +++ b/src/test/ui/rust-2018/async-ident.fixed @@ -9,7 +9,7 @@ // except according to those terms. #![allow(dead_code, unused_variables, non_camel_case_types, non_upper_case_globals)] -#![deny(async_idents)] +#![deny(keyword_idents)] // edition:2015 // run-rustfix diff --git a/src/test/ui/rust-2018/async-ident.rs b/src/test/ui/rust-2018/async-ident.rs index 6087d2c1642..069da7ffcdd 100644 --- a/src/test/ui/rust-2018/async-ident.rs +++ b/src/test/ui/rust-2018/async-ident.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(dead_code, unused_variables, non_camel_case_types, non_upper_case_globals)] -#![deny(async_idents)] +#![deny(keyword_idents)] // edition:2015 // run-rustfix diff --git a/src/test/ui/rust-2018/async-ident.stderr b/src/test/ui/rust-2018/async-ident.stderr index 06d68a38c5f..b9bb2e254b4 100644 --- a/src/test/ui/rust-2018/async-ident.stderr +++ b/src/test/ui/rust-2018/async-ident.stderr @@ -7,8 +7,8 @@ LL | fn async() {} //~ ERROR async note: lint level defined here --> $DIR/async-ident.rs:12:9 | -LL | #![deny(async_idents)] - | ^^^^^^^^^^^^ +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 diff --git a/src/test/ui/rust-2018/try-ident.fixed b/src/test/ui/rust-2018/try-ident.fixed new file mode 100644 index 00000000000..96a0cd0f8e9 --- /dev/null +++ b/src/test/ui/rust-2018/try-ident.fixed @@ -0,0 +1,21 @@ +// 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. + +// run-rustfix +// compile-pass + +#![warn(rust_2018_compatibility)] + +fn main() { + r#try(); +} + +fn r#try() { +} diff --git a/src/test/ui/rust-2018/try-ident.rs b/src/test/ui/rust-2018/try-ident.rs new file mode 100644 index 00000000000..ade2e03ff22 --- /dev/null +++ b/src/test/ui/rust-2018/try-ident.rs @@ -0,0 +1,21 @@ +// 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. + +// run-rustfix +// compile-pass + +#![warn(rust_2018_compatibility)] + +fn main() { + try(); +} + +fn try() { +} diff --git a/src/test/ui/rust-2018/try-ident.stderr b/src/test/ui/rust-2018/try-ident.stderr new file mode 100644 index 00000000000..72bd81530df --- /dev/null +++ b/src/test/ui/rust-2018/try-ident.stderr @@ -0,0 +1,24 @@ +warning: `try` is a keyword in the 2018 edition + --> $DIR/try-ident.rs:17:5 + | +LL | try(); + | ^^^ help: you can use a raw identifier to stay compatible: `r#try` + | +note: lint level defined here + --> $DIR/try-ident.rs:14:9 + | +LL | #![warn(rust_2018_compatibility)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: #[warn(keyword_idents)] implied by #[warn(rust_2018_compatibility)] + = 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 + +warning: `try` is a keyword in the 2018 edition + --> $DIR/try-ident.rs:20:4 + | +LL | fn try() { + | ^^^ help: you can use a raw identifier to stay compatible: `r#try` + | + = 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 +