2
2
3
3
## Summary
4
4
5
- - ` $_:pat ` in ` macro_rules ` now matches ` | ` too: e.g. ` A | B ` .
6
- - ` $_:pat_param ` behaves like ` $_:pat ` did before; it does not match (top level) ` | ` .
7
- - ` $_:pat_param ` is available in all editions.
5
+ - How patterns work in ` macro_rules ` macros changes slightly:
6
+ - `$_:pat` in `macro_rules` now matches usage of `|` too: e.g. `A | B`.
7
+ - The new `$_:pat_param` behaves like `$_:pat` did before; it does not match (top level) `|`.
8
+ - `$_:pat_param` is available in all editions.
8
9
9
10
## Details
10
11
@@ -15,18 +16,57 @@ Since this was simply not allowed before, this is not a breaking change.
15
16
16
17
However, this change also affects [ ` macro_rules ` macros] ( https://doc.rust-lang.org/stable/reference/macros-by-example.html ) .
17
18
Such macros can accept patterns using the ` :pat ` fragment specifier.
18
- Currently, ` :pat ` does * not* match ` | ` , since before Rust 1.53,
19
+ Currently, ` :pat ` does * not* match top level ` | ` , since before Rust 1.53,
19
20
not all patterns (at all nested levels) could contain a ` | ` .
20
21
Macros that accept patterns like ` A | B ` ,
21
22
such as [ ` matches!() ` ] ( https://doc.rust-lang.org/1.51.0/std/macro.matches.html )
22
- use something like ` $($_:pat)|+ ` .
23
- Because we don't want to break any existing macros,
24
- we did * not* change the meaning of ` :pat ` in Rust 1.53.0 to include ` | ` .
23
+ use something like ` $($_:pat)|+ ` .
25
24
26
- Instead, we will make that change as part of Rust 2021.
25
+ Because this would potentially break existing macros, the meaning of ` :pat ` did
26
+ not change in Rust 1.53.0 to include ` | ` . Instead, that change happens in Rust 2021.
27
27
In the new edition, the ` :pat ` fragment specifier * will* match ` A | B ` .
28
28
29
- Since there are times that one still wishes to match a single pattern
30
- variant without ` | ` , the fragment specified ` :pat_param ` has been added
31
- to retain the older behavior.
32
- The name refers to its main use case: a pattern in a closure parameter.
29
+ ` $_:pat ` fragments in Rust 2021 cannot be followed by an explicit ` | ` . Since there are times
30
+ that one still wishes to match pattern fragments followed by a ` | ` , the fragment specified ` :pat_param `
31
+ has been added to retain the older behavior.
32
+
33
+ It's important to remember that editions are _ per crate_ , so the only relevant edition is the edition
34
+ of the crate where the macro is defined. The edition of the crate where the macro is used does not
35
+ change how the macro works.
36
+
37
+ ## Migration to Rust 2021
38
+
39
+ A lint, ` rust_2021_incompatible_or_patterns ` , gets triggered whenever there is a use ` $:_pat ` which
40
+ will change meaning in Rust 2021.
41
+
42
+ You can automatically migrate your code to be Rust 2021 Edition compatible or ensure it is already compatible by
43
+ running:
44
+
45
+ ``` sh
46
+ cargo fix --edition
47
+ ```
48
+
49
+ If you have a macro which relies on ` $_:pat ` not matching the top level use of ` | ` in patterns,
50
+ you'll need to change each occurrence of ` $_:pat ` to ` $_:pat_param ` .
51
+
52
+ For example:
53
+
54
+ ``` rust
55
+ macro_rules! my_macro {
56
+ ($ x : pat | $ y : pat ) => {
57
+ // TODO: implementation
58
+ }
59
+ }
60
+
61
+ // This macro works in Rust 2018 since `$x:pat` does not match against `|`:
62
+ my_macro! (1 | 2 );
63
+
64
+ // In Rust 2021 however, the `$_:pat` fragment matches `|` and is not allowed
65
+ // to be followed by a `|`. To make sure this macro still works in Rust 2021
66
+ // change the macro to the following:
67
+ macro_rules! my_macro {
68
+ ($ x : pat _param | $ y : pat ) => { // <- this line is different
69
+ // TODO: implementation
70
+ }
71
+ }
72
+ ```
0 commit comments