Home Explore Blog CI



rustc

2nd chunk of `src/guides/editions.md`
5c7ad3e4157ed400562123c704e82a3a42f2496eb01a37ed0000000100000fb1
  This requires the user to still specify `#![feature(my_feature)]`, to avoid disrupting testing of
  other edition features which are ready and have been accepted within the edition.

- For experimental features that have graduated to definitely be part of an edition,
  they should implement gates with `tcx.features().my_feature || span.at_least_rust_20xx()`,
  or just remove the feature check altogether and just check `span.at_least_rust_20xx()`.

If you need to do the feature gating in multiple places, consider placing the check in a single
function so that there will only be a single place to update. For example:

```rust,ignore
// An example from Edition 2021 disjoint closure captures.

fn enable_precise_capture(tcx: TyCtxt<'_>, span: Span) -> bool {
    tcx.features().capture_disjoint_fields || span.rust_2021()
}
```

See [Lints and stability](#lints-and-stability) below for more information about how lints handle
stability.


## Edition parsing

For the most part, the lexer is edition-agnostic.
Within [`Lexer`], tokens can be modified based on edition-specific behavior.
For example, C-String literals like `c"foo"` are split into multiple tokens in editions before 2021.
This is also where things like reserved prefixes are handled for the 2021 edition.

Edition-specific parsing is relatively rare. One example is `async fn` which checks the span of the
token to determine if it is the 2015 edition, and emits an error in that case.
This can only be done if the syntax was already invalid.

If you need to do edition checking in the parser, you will normally want to look at the edition of
the token, see [Edition hygiene].
In some rare cases you may instead need to check the global edition from [`ParseSess::edition`].

Most edition-specific parsing behavior is handled with [migration lints] instead of in the parser.
This is appropriate when there is a *change* in syntax (as opposed to new syntax).
This allows the old syntax to continue to work on previous editions.
The lint then checks for the change in behavior.
On older editions, the lint pass should emit the migration lint to help with migrating to new
editions.
On newer editions, your code should emit a hard error with `emit_err` instead.
For example, the deprecated `start...end` pattern syntax emits the
[`ellipsis_inclusive_range_patterns`] lint on editions before 2021, and in 2021 is an hard error via
the `emit_err` method.


### Keywords

New keywords can be introduced across an edition boundary.
This is implemented by functions like [`Symbol::is_used_keyword_conditional`], which rely on the
ordering of how the keywords are defined.

When new keywords are introduced, the [`keyword_idents`] lint should be updated so that automatic
migrations can transition code that might be using the keyword as an identifier (see
[`KeywordIdents`]).
An alternative to consider is to implement the keyword as a weak keyword if the position it is used
is sufficient to distinguish it.

An additional option to consider is the `k#` prefix which was introduced in [RFC 3101].
This allows the use of a keyword in editions *before* the edition where the keyword is introduced.
This is currently not implemented.


### Edition hygiene

Spans are marked with the edition of the crate that the span came from.
See [Macro hygiene] in the Edition Guide for a user-centric description of what this means.

You should normally use the edition from the token span instead of looking at the global `Session`
edition.
For example, use `span.edition().at_least_rust_2021()` instead of `sess.at_least_rust_2021()`.
This helps ensure that macros behave correctly when used across crates.


## Lints

Lints support a few different options for interacting with editions.
Lints can be *future incompatible edition migration lints*, which are used to support
[migrations][migration lints] to newer editions.
Alternatively, lints can be [edition-specific](#edition-specific-lints), where they change their
default level starting in a specific edition.

Title: Edition Parsing and Hygiene, Keywords and Lints
Summary
This section continues the discussion of Rust editions, focusing on parsing, hygiene, keywords, and lints. Experimental features that are definitely part of an edition should use feature gates or just check the edition. Code examples illustrate how to enable features based on edition. The lexer is mostly edition-agnostic, but tokens can be modified based on the edition. Edition-specific parsing is rare, and migration lints are often used for syntax changes. New keywords can be introduced across edition boundaries, and the `keyword_idents` lint helps with migrations. Span editions should be used instead of the global session edition for hygiene. Lints support migration and edition-specific behavior.