Macro Fragment Specifiers
Summary
- The
expr
fragment specifier now also supportsconst
and_
expressions. - The
expr_2021
fragment specifier has been added for backwards compatibility.
Details
As new syntax is added to Rust, existing macro_rules
fragment specifiers are sometimes not allowed to match on the new syntax in order to retain backwards compatibility. Supporting the new syntax in the old fragment specifiers is sometimes deferred until the next edition, which provides an opportunity to update them.
Indeed this happened with const
expressions added in 1.79 and _
expressions added in 1.59. In the 2021 Edition and earlier, the expr
fragment specifier does not match those expressions. This is because you may have a scenario like:
macro_rules! example { ($e:expr) => { println!("first rule"); }; (const $e:expr) => { println!("second rule"); }; } fn main() { example!(const { 1 + 1 }); }
Here, in the 2021 Edition, the macro will match the second rule. If earlier editions had changed expr
to match the newly introduced const
expressions, then it would match the first rule, which would be a breaking change.
In the 2024 Edition, expr
specifiers now also match const
and _
expressions. To support the old behavior, the expr_2021
fragment specifier has been added which does not match the new expressions.
Migration
The edition_2024_expr_fragment_specifier
lint will change all uses of the expr
specifier to expr_2021
to ensure that the behavior of existing macros does not change. The lint is part of the rust-2024-compatibility
lint group which is included in the automatic edition migration. In order to migrate your code to be Rust 2024 Edition compatible, run:
cargo fix --edition
In most cases, you will likely want to keep the expr
specifier instead, in order to support the new expressions. You will need to review your macro to determine if there are other rules that would otherwise match with const
or _
and determine if there is a conflict. If you want the new behavior, just revert any changes made by the lint.
Alternatively, you can manually enable the lint to find macros where you may need to update the expr
specifier.
#![allow(unused)] fn main() { // Add this to the root of your crate to do a manual migration. #![warn(edition_2024_expr_fragment_specifier)] }