# Editions
<!-- toc -->
This chapter gives an overview of how Edition support works in rustc.
This assumes that you are familiar with what Editions are (see the [Edition Guide]).
## Edition definition
The `--edition` CLI flag specifies the edition to use for a crate.
This can be accessed from [`Session::edition`].
There are convenience functions like [`Session::at_least_rust_2021`] for checking the crate's
edition, though you should be careful about whether you check the global session or the span, see
[Edition hygiene] below.
As an alternative to the `at_least_rust_20xx` convenience methods, the [`Edition`] type also
supports comparisons for doing range checks, such as `span.edition() >= Edition::Edition2021`.
### Adding a new edition
Adding a new edition mainly involves adding a variant to the [`Edition`] enum and then fixing
everything that is broken. See [#94461](https://github.com/rust-lang/rust/pull/94461) for an
example.
### Features and Edition stability
The [`Edition`] enum defines whether or not an edition is stable.
If it is not stable, then the `-Zunstable-options` CLI option must be passed to enable it.
When adding a new feature, there are two options you can choose for how to handle stability with a
future edition:
- Just check the edition of the span like `span.at_least_rust_20xx()` (see [Edition hygiene]) or the
[`Session::edition`]. This will implicitly depend on the stability of the edition itself to
indicate that your feature is available.
- Place your new behavior behind a [feature gate].
It may be sufficient to only check the current edition for relatively simple changes.
However, for larger language changes, you should consider creating a feature gate.
There are several benefits to using a feature gate:
- A feature gate makes it easier to work on and experiment with a new feature.
- It makes the intent clear when the `#![feature(…)]` attribute is used that your new feature is
being enabled.
- It makes testing of editions easier so that features that are not yet complete do not interfere
with testing of edition-specific features that are complete and ready.
- It decouples the feature from an edition, which makes it easier for the team to make a deliberate
decision of whether or not a feature should be added to the next edition when the feature is
ready.
When a feature is complete and ready, the feature gate can be removed (and the code should just
check the span or `Session` edition to determine if it is enabled).
There are a few different options for doing feature checks:
- For highly experimental features, that may or may not be involved in an edition, they can
implement regular feature gates like `tcx.features().my_feature`, and ignore editions for the time
being.
- For experimental features that *might* be involved in an edition, they should implement gates with
`tcx.features().my_feature && span.at_least_rust_20xx()`.
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.