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.
### Migration lints
*Migration lints* are used to migrate projects from one edition to the next.
They are implemented with a `MachineApplicable` [suggestion](../diagnostics.md#suggestions) which
will rewrite code so that it will **successfully compile in both the previous and the next
edition**.
For example, the [`keyword_idents`] lint will take identifiers that conflict with a new keyword to
use the raw identifier syntax to avoid the conflict (for example changing `async` to `r#async`).
Migration lints must be declared with the [`FutureIncompatibilityReason::EditionError`] or
[`FutureIncompatibilityReason::EditionSemanticsChange`] [future-incompatible
option](../diagnostics.md#future-incompatible-lints) in the lint declaration:
```rust,ignore
declare_lint! {
pub KEYWORD_IDENTS,
Allow,
"detects edition keywords being used as an identifier",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
};
}
```
When declared like this, the lint is automatically added to the appropriate
`rust-20xx-compatibility` lint group.
When a user runs `cargo fix --edition`, cargo will pass the `--force-warn rust-20xx-compatibility`
flag to force all of these lints to appear during the edition migration.
Cargo also passes `--cap-lints=allow` so that no other lints interfere with the edition migration.
Make sure that the example code sets the correct edition. The example should illustrate the previous edition, and show what the migration warning would look like. For example, this lint for a 2024 migration shows an example in 2021:
```rust,ignore
declare_lint! {
/// The `keyword_idents_2024` lint detects ...
///
/// ### Example
///
/// ```rust,edition2021
/// #![warn(keyword_idents_2024)]
/// fn gen() {}
/// ```
///
/// {{produces}}
}
```
Migration lints can be either `Allow` or `Warn` by default.
If it is `Allow`, users usually won't see this warning unless they are doing an edition migration
manually or there is a problem during the migration.
Most migration lints are `Allow`.
If it is `Warn` by default, users on all editions will see this warning.
Only use `Warn` if you think it is important for everyone to be aware of the change, and to
encourage people to update their code on all editions.
Beware that new warn-by-default lint that hit many projects can be very disruptive and frustrating
for users.
You may consider switching an `Allow` to `Warn` several years after the edition stabilizes.
This will only show up for the relatively small number of stragglers who have not updated to the new
edition.
[`keyword_idents`]: https://doc.rust-lang.org/nightly/rustc/lints/listing/allowed-by-default.html#keyword-idents
[`FutureIncompatibilityReason::EditionError`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.FutureIncompatibilityReason.html#variant.EditionError