Deny gen keyword in edition_2024_compat lints

This commit is contained in:
Michael Goulet 2024-04-09 10:36:58 -04:00
parent 7f2fc33da6
commit 7789874e6e
16 changed files with 156 additions and 34 deletions

View File

@ -1769,13 +1769,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
}
declare_lint! {
/// The `keyword_idents` lint detects edition keywords being used as an
/// The `keyword_idents_2018` lint detects edition keywords being used as an
/// identifier.
///
/// ### Example
///
/// ```rust,edition2015,compile_fail
/// #![deny(keyword_idents)]
/// #![deny(keyword_idents_2018)]
/// // edition 2015
/// fn dyn() {}
/// ```
@ -1804,7 +1804,7 @@ declare_lint! {
/// [editions]: https://doc.rust-lang.org/edition-guide/
/// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
/// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
pub KEYWORD_IDENTS,
pub KEYWORD_IDENTS_2018,
Allow,
"detects edition keywords being used as an identifier",
@future_incompatible = FutureIncompatibleInfo {
@ -1813,9 +1813,54 @@ declare_lint! {
};
}
declare_lint! {
/// The `keyword_idents_2024` lint detects edition keywords being used as an
/// identifier.
///
/// ### Example
///
/// ```rust,edition2015,compile_fail
/// #![deny(keyword_idents_2024)]
/// // edition 2015
/// fn gen() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Rust [editions] allow the language to evolve without breaking
/// backwards compatibility. This lint catches code that uses new keywords
/// that are added to the language that are used as identifiers (such as a
/// variable name, function name, etc.). If you switch the compiler to a
/// new edition without updating the code, then it will fail to compile if
/// you are using a new keyword as an identifier.
///
/// You can manually change the identifiers to a non-keyword, or use a
/// [raw identifier], for example `r#gen`, to transition to a new edition.
///
/// This lint solves the problem automatically. It is "allow" by default
/// because the code is perfectly valid in older editions. The [`cargo
/// fix`] tool with the `--edition` flag will switch this lint to "warn"
/// and automatically apply the suggested fix from the compiler (which is
/// to use a raw identifier). This provides a completely automated way to
/// update old code for a new edition.
///
/// [editions]: https://doc.rust-lang.org/edition-guide/
/// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
/// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
pub KEYWORD_IDENTS_2024,
Allow,
"detects edition keywords being used as an identifier",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
};
}
declare_lint_pass!(
/// Check for uses of edition keywords used as an identifier.
KeywordIdents => [KEYWORD_IDENTS]
KeywordIdents => [KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024]
);
struct UnderMacro(bool);
@ -1841,42 +1886,39 @@ impl KeywordIdents {
UnderMacro(under_macro): UnderMacro,
ident: Ident,
) {
let next_edition = match cx.sess().edition() {
Edition::Edition2015 => {
match ident.name {
kw::Async | kw::Await | kw::Try => Edition::Edition2018,
let (lint, edition) = match ident.name {
kw::Async | kw::Await | kw::Try => (KEYWORD_IDENTS_2018, Edition::Edition2018),
// rust-lang/rust#56327: Conservatively do not
// attempt to report occurrences of `dyn` within
// macro definitions or invocations, because `dyn`
// can legitimately occur as a contextual keyword
// in 2015 code denoting its 2018 meaning, and we
// do not want rustfix to inject bugs into working
// code by rewriting such occurrences.
//
// But if we see `dyn` outside of a macro, we know
// its precise role in the parsed AST and thus are
// assured this is truly an attempt to use it as
// an identifier.
kw::Dyn if !under_macro => Edition::Edition2018,
// rust-lang/rust#56327: Conservatively do not
// attempt to report occurrences of `dyn` within
// macro definitions or invocations, because `dyn`
// can legitimately occur as a contextual keyword
// in 2015 code denoting its 2018 meaning, and we
// do not want rustfix to inject bugs into working
// code by rewriting such occurrences.
//
// But if we see `dyn` outside of a macro, we know
// its precise role in the parsed AST and thus are
// assured this is truly an attempt to use it as
// an identifier.
kw::Dyn if !under_macro => (KEYWORD_IDENTS_2018, Edition::Edition2018),
_ => return,
}
}
kw::Gen => (KEYWORD_IDENTS_2024, Edition::Edition2024),
// There are no new keywords yet for the 2018 edition and beyond.
_ => return,
};
// Don't lint `r#foo`.
if cx.sess().psess.raw_identifier_spans.contains(ident.span) {
if ident.span.edition() >= edition
|| cx.sess().psess.raw_identifier_spans.contains(ident.span)
{
return;
}
cx.emit_span_lint(
KEYWORD_IDENTS,
lint,
ident.span,
BuiltinKeywordIdents { kw: ident, next: next_edition, suggestion: ident.span },
BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span },
);
}
}

View File

@ -313,6 +313,8 @@ fn register_builtins(store: &mut LintStore) {
// MACRO_USE_EXTERN_CRATE
);
add_lint_group!("keyword_idents", KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024);
add_lint_group!(
"refining_impl_trait",
REFINING_IMPL_TRAIT_REACHABLE,
@ -325,7 +327,7 @@ fn register_builtins(store: &mut LintStore) {
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_renamed("async_idents", "keyword_idents_2018");
store.register_renamed("exceeding_bitshifts", "arithmetic_overflow");
store.register_renamed("redundant_semicolon", "redundant_semicolons");
store.register_renamed("overlapping_patterns", "overlapping_range_endpoints");

View File

@ -20,6 +20,10 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
"refining-impl-trait",
"Detects refinement of `impl Trait` return types by trait implementations",
),
(
"keyword-idents",
"Lints that detect identifiers which will be come keywords in later editions",
),
];
type LintGroups = BTreeMap<String, BTreeSet<String>>;

View File

@ -25,6 +25,7 @@ static RENAMES: &[(Level, &[(&str, &str)])] = &[
("elided-lifetime-in-path", "elided-lifetimes-in-paths"),
("async-idents", "keyword-idents"),
("disjoint-capture-migration", "rust-2021-incompatible-closure-captures"),
("keyword-idents", "keyword-idents-2018"),
("or-patterns-back-compat", "rust-2021-incompatible-or-patterns"),
],
),

View File

@ -11,6 +11,7 @@ note: the lint level is defined here
|
LL | #![deny(keyword_idents)]
| ^^^^^^^^^^^^^^
= note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]`
error: `await` is a keyword in the 2018 edition
--> $DIR/2015-edition-error-various-positions.rs:7:20

View File

@ -11,6 +11,7 @@ note: the lint level is defined here
|
LL | #![deny(keyword_idents)]
| ^^^^^^^^^^^^^^
= note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]`
error: `await` is a keyword in the 2018 edition
--> $DIR/2015-edition-warning.rs:10:20

View File

@ -11,6 +11,7 @@ note: the lint level is defined here
|
LL | #![deny(keyword_idents)]
| ^^^^^^^^^^^^^^
= note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]`
error: `dyn` is a keyword in the 2018 edition
--> $DIR/dyn-2015-edition-keyword-ident-lint.rs:17:20

View File

@ -6,8 +6,8 @@ LL | pub fn try() {}
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
= note: `-W keyword-idents` implied by `-W rust-2018-compatibility`
= help: to override `-W rust-2018-compatibility` add `#[allow(keyword_idents)]`
= note: `-W keyword-idents-2018` implied by `-W rust-2018-compatibility`
= help: to override `-W rust-2018-compatibility` add `#[allow(keyword_idents_2018)]`
warning: 1 warning emitted

View File

@ -11,7 +11,7 @@ note: the lint level is defined here
|
LL | #![deny(rust_2018_compatibility)]
| ^^^^^^^^^^^^^^^^^^^^^^^
= note: `#[deny(keyword_idents)]` implied by `#[deny(rust_2018_compatibility)]`
= note: `#[deny(keyword_idents_2018)]` implied by `#[deny(rust_2018_compatibility)]`
error: aborting due to 1 previous error

View File

@ -11,6 +11,7 @@ note: the lint level is defined here
|
LL | #![deny(keyword_idents)]
| ^^^^^^^^^^^^^^
= note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]`
error: `async` is a keyword in the 2018 edition
--> $DIR/async-ident.rs:12:7

View File

@ -11,6 +11,7 @@ note: the lint level is defined here
|
LL | #![deny(keyword_idents)]
| ^^^^^^^^^^^^^^
= note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]`
error: aborting due to 1 previous error

View File

@ -11,7 +11,7 @@ note: the lint level is defined here
|
LL | #![warn(rust_2018_compatibility)]
| ^^^^^^^^^^^^^^^^^^^^^^^
= note: `#[warn(keyword_idents)]` implied by `#[warn(rust_2018_compatibility)]`
= note: `#[warn(keyword_idents_2018)]` implied by `#[warn(rust_2018_compatibility)]`
warning: `try` is a keyword in the 2018 edition
--> $DIR/try-ident.rs:12:4

View File

@ -11,7 +11,7 @@ note: the lint level is defined here
|
LL | #![warn(rust_2018_compatibility)]
| ^^^^^^^^^^^^^^^^^^^^^^^
= note: `#[warn(keyword_idents)]` implied by `#[warn(rust_2018_compatibility)]`
= note: `#[warn(keyword_idents_2018)]` implied by `#[warn(rust_2018_compatibility)]`
warning: 1 warning emitted

View File

@ -0,0 +1,26 @@
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:6:4
|
LL | fn gen() {}
| ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
note: the lint level is defined here
--> $DIR/gen-kw.rs:4:9
|
LL | #![deny(rust_2024_compatibility)]
| ^^^^^^^^^^^^^^^^^^^^^^^
= note: `#[deny(keyword_idents_2024)]` implied by `#[deny(rust_2024_compatibility)]`
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:12:9
|
LL | let gen = r#gen;
| ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
error: aborting due to 2 previous errors

View File

@ -0,0 +1,26 @@
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:6:4
|
LL | fn gen() {}
| ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
note: the lint level is defined here
--> $DIR/gen-kw.rs:4:9
|
LL | #![deny(rust_2024_compatibility)]
| ^^^^^^^^^^^^^^^^^^^^^^^
= note: `#[deny(keyword_idents_2024)]` implied by `#[deny(rust_2024_compatibility)]`
error: `gen` is a keyword in the 2024 edition
--> $DIR/gen-kw.rs:12:9
|
LL | let gen = r#gen;
| ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
error: aborting due to 2 previous errors

View File

@ -0,0 +1,16 @@
//@ revisions: e2015 e2018
//@[e2018] edition: 2018
#![deny(rust_2024_compatibility)]
fn gen() {}
//~^ ERROR `gen` is a keyword in the 2024 edition
//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
//[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
fn main() {
let gen = r#gen;
//~^ ERROR `gen` is a keyword in the 2024 edition
//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
//[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
}