Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deny gen keyword in edition_2024_compat lints #123680

Merged
merged 1 commit into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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!
}
Loading