Skip to content

Commit

Permalink
Deny gen keyword in edition_2024_compat lints
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Apr 22, 2024
1 parent 7f2fc33 commit 7789874
Show file tree
Hide file tree
Showing 16 changed files with 158 additions and 36 deletions.
102 changes: 72 additions & 30 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
/// ```
Expand Down Expand Up @@ -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 {
Expand All @@ -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);
Expand All @@ -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,

// 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,

_ => return,
}
}
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 => (KEYWORD_IDENTS_2018, Edition::Edition2018),

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 },
);
}
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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");
Expand Down
4 changes: 4 additions & 0 deletions src/tools/lint-docs/src/groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>;
Expand Down
1 change: 1 addition & 0 deletions src/tools/lint-docs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
],
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/lint/lint-pre-expansion-extern-module.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

2 changes: 1 addition & 1 deletion tests/ui/rust-2018/async-ident-allowed.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

1 change: 1 addition & 0 deletions tests/ui/rust-2018/async-ident.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions tests/ui/rust-2018/dyn-keyword.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

2 changes: 1 addition & 1 deletion tests/ui/rust-2018/try-ident.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/rust-2018/try-macro.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

26 changes: 26 additions & 0 deletions tests/ui/rust-2024/gen-kw.e2015.stderr
Original file line number Diff line number Diff line change
@@ -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

26 changes: 26 additions & 0 deletions tests/ui/rust-2024/gen-kw.e2018.stderr
Original file line number Diff line number Diff line change
@@ -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

16 changes: 16 additions & 0 deletions tests/ui/rust-2024/gen-kw.rs
Original file line number Diff line number Diff line change
@@ -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!
}

0 comments on commit 7789874

Please sign in to comment.