@@ -1769,13 +1769,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
17691769}
17701770
17711771declare_lint ! {
1772- /// The `keyword_idents ` lint detects edition keywords being used as an
1772+ /// The `keyword_idents_2018 ` lint detects edition keywords being used as an
17731773 /// identifier.
17741774 ///
17751775 /// ### Example
17761776 ///
17771777 /// ```rust,edition2015,compile_fail
1778- /// #![deny(keyword_idents )]
1778+ /// #![deny(keyword_idents_2018 )]
17791779 /// // edition 2015
17801780 /// fn dyn() {}
17811781 /// ```
@@ -1804,7 +1804,7 @@ declare_lint! {
18041804 /// [editions]: https://doc.rust-lang.org/edition-guide/
18051805 /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
18061806 /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
1807- pub KEYWORD_IDENTS ,
1807+ pub KEYWORD_IDENTS_2018 ,
18081808 Allow ,
18091809 "detects edition keywords being used as an identifier" ,
18101810 @future_incompatible = FutureIncompatibleInfo {
@@ -1813,9 +1813,54 @@ declare_lint! {
18131813 } ;
18141814}
18151815
1816+ declare_lint ! {
1817+ /// The `keyword_idents_2024` lint detects edition keywords being used as an
1818+ /// identifier.
1819+ ///
1820+ /// ### Example
1821+ ///
1822+ /// ```rust,edition2015,compile_fail
1823+ /// #![deny(keyword_idents_2024)]
1824+ /// // edition 2015
1825+ /// fn gen() {}
1826+ /// ```
1827+ ///
1828+ /// {{produces}}
1829+ ///
1830+ /// ### Explanation
1831+ ///
1832+ /// Rust [editions] allow the language to evolve without breaking
1833+ /// backwards compatibility. This lint catches code that uses new keywords
1834+ /// that are added to the language that are used as identifiers (such as a
1835+ /// variable name, function name, etc.). If you switch the compiler to a
1836+ /// new edition without updating the code, then it will fail to compile if
1837+ /// you are using a new keyword as an identifier.
1838+ ///
1839+ /// You can manually change the identifiers to a non-keyword, or use a
1840+ /// [raw identifier], for example `r#gen`, to transition to a new edition.
1841+ ///
1842+ /// This lint solves the problem automatically. It is "allow" by default
1843+ /// because the code is perfectly valid in older editions. The [`cargo
1844+ /// fix`] tool with the `--edition` flag will switch this lint to "warn"
1845+ /// and automatically apply the suggested fix from the compiler (which is
1846+ /// to use a raw identifier). This provides a completely automated way to
1847+ /// update old code for a new edition.
1848+ ///
1849+ /// [editions]: https://doc.rust-lang.org/edition-guide/
1850+ /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
1851+ /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
1852+ pub KEYWORD_IDENTS_2024 ,
1853+ Allow ,
1854+ "detects edition keywords being used as an identifier" ,
1855+ @future_incompatible = FutureIncompatibleInfo {
1856+ reason: FutureIncompatibilityReason :: EditionError ( Edition :: Edition2024 ) ,
1857+ reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>" ,
1858+ } ;
1859+ }
1860+
18161861declare_lint_pass ! (
18171862 /// Check for uses of edition keywords used as an identifier.
1818- KeywordIdents => [ KEYWORD_IDENTS ]
1863+ KeywordIdents => [ KEYWORD_IDENTS_2018 , KEYWORD_IDENTS_2024 ]
18191864) ;
18201865
18211866struct UnderMacro ( bool ) ;
@@ -1841,42 +1886,39 @@ impl KeywordIdents {
18411886 UnderMacro ( under_macro) : UnderMacro ,
18421887 ident : Ident ,
18431888 ) {
1844- let next_edition = match cx. sess ( ) . edition ( ) {
1845- Edition :: Edition2015 => {
1846- match ident. name {
1847- kw:: Async | kw:: Await | kw:: Try => Edition :: Edition2018 ,
1848-
1849- // rust-lang/rust#56327: Conservatively do not
1850- // attempt to report occurrences of `dyn` within
1851- // macro definitions or invocations, because `dyn`
1852- // can legitimately occur as a contextual keyword
1853- // in 2015 code denoting its 2018 meaning, and we
1854- // do not want rustfix to inject bugs into working
1855- // code by rewriting such occurrences.
1856- //
1857- // But if we see `dyn` outside of a macro, we know
1858- // its precise role in the parsed AST and thus are
1859- // assured this is truly an attempt to use it as
1860- // an identifier.
1861- kw:: Dyn if !under_macro => Edition :: Edition2018 ,
1862-
1863- _ => return ,
1864- }
1865- }
1889+ let ( lint, edition) = match ident. name {
1890+ kw:: Async | kw:: Await | kw:: Try => ( KEYWORD_IDENTS_2018 , Edition :: Edition2018 ) ,
1891+
1892+ // rust-lang/rust#56327: Conservatively do not
1893+ // attempt to report occurrences of `dyn` within
1894+ // macro definitions or invocations, because `dyn`
1895+ // can legitimately occur as a contextual keyword
1896+ // in 2015 code denoting its 2018 meaning, and we
1897+ // do not want rustfix to inject bugs into working
1898+ // code by rewriting such occurrences.
1899+ //
1900+ // But if we see `dyn` outside of a macro, we know
1901+ // its precise role in the parsed AST and thus are
1902+ // assured this is truly an attempt to use it as
1903+ // an identifier.
1904+ kw:: Dyn if !under_macro => ( KEYWORD_IDENTS_2018 , Edition :: Edition2018 ) ,
1905+
1906+ kw:: Gen => ( KEYWORD_IDENTS_2024 , Edition :: Edition2024 ) ,
18661907
1867- // There are no new keywords yet for the 2018 edition and beyond.
18681908 _ => return ,
18691909 } ;
18701910
18711911 // Don't lint `r#foo`.
1872- if cx. sess ( ) . psess . raw_identifier_spans . contains ( ident. span ) {
1912+ if ident. span . edition ( ) >= edition
1913+ || cx. sess ( ) . psess . raw_identifier_spans . contains ( ident. span )
1914+ {
18731915 return ;
18741916 }
18751917
18761918 cx. emit_span_lint (
1877- KEYWORD_IDENTS ,
1919+ lint ,
18781920 ident. span ,
1879- BuiltinKeywordIdents { kw : ident, next : next_edition , suggestion : ident. span } ,
1921+ BuiltinKeywordIdents { kw : ident, next : edition , suggestion : ident. span } ,
18801922 ) ;
18811923 }
18821924}
0 commit comments