]> git.proxmox.com Git - rustc.git/blob - src/doc/edition-guide/src/rust-2021/or-patterns-macro-rules.md
New upstream version 1.55.0+dfsg1
[rustc.git] / src / doc / edition-guide / src / rust-2021 / or-patterns-macro-rules.md
1 # Or patterns in macro-rules
2
3 ## Summary
4
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.
9
10 ## Details
11
12 Starting in Rust 1.53.0, [patterns](https://doc.rust-lang.org/stable/reference/patterns.html)
13 are extended to support `|` nested anywhere in the pattern.
14 This enables you to write `Some(1 | 2)` instead of `Some(1) | Some(2)`.
15 Since this was simply not allowed before, this is not a breaking change.
16
17 However, this change also affects [`macro_rules` macros](https://doc.rust-lang.org/stable/reference/macros-by-example.html).
18 Such macros can accept patterns using the `:pat` fragment specifier.
19 Currently, `:pat` does *not* match top level `|`, since before Rust 1.53,
20 not all patterns (at all nested levels) could contain a `|`.
21 Macros that accept patterns like `A | B`,
22 such as [`matches!()`](https://doc.rust-lang.org/1.51.0/std/macro.matches.html)
23 use something like `$($_:pat)|+`.
24
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 In the new edition, the `:pat` fragment specifier *will* match `A | B`.
28
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 ```