When or-patterns are present in a pattern, the drop order for its bindings depends on the particular language construct used. To see it in action, see [this test](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=190a0f41f5af1089cfa623894635e62e) (#142193), but in short: - `let pat;` treats the bindings in `pat` as being in the order they first appear in the pattern, and drops them in reverse order. This is the behavior I would expect. ```rust // Drops are right-to-left: `z`, `y`, `x`. let (x, Ok(y) | Err(y), z); // The first or-pattern alternative determines the bindings' drop order: `y`, `x`. let ((true, x, y) | (false, y, x)); ``` - `let pat = expr;`, `if let`, and `let`-`else` see bindings in or-patterns as being after other bindings, thus they're dropped first. i.e. ```rust // Drops are right-to-left, treating `y` as rightmost: `y`, `z`, `x`. let (x, Ok(y) | Err(y), z) = expr; // The first or-pattern alternative determines the bindings' drop order: `y`, `x`. let ((true, x, y) | (false, y, x)) = expr; ``` - `match` arms see bindings in or-patterns as being after other bindings, and use the final or-pattern alternative's binding order, rather than the first. i.e. ```rust // Drops are right-to-left, treating `y` as rightmost: `y`, `z`, `x`. match expr { (x, Ok(y) | Err(y), z) => {} } // The last or-pattern alternative determines the bindings' drop order: `x`, `y`. match expr { (true, x, y) | (false, y, x) => {} } ``` - Function parameters are dropped in the usual right-to-left order, but the bindings within a parameter's pattern see bindings in or-patterns as being rightmost. i.e. ```rust // Among separate params, the drop order is right-to-left: `z`, `y`, `x`. (|x, (Ok(y) | Err(y)), z| {})(expr1, expr2, expr3); // Within a param's pattern, or-patterns are treated as rightmost: `y`, `z`, `x`. (|(x, Ok(y) | Err(y), z)| {})(expr); // The first or-pattern alternative determines the bindings' drop order: `y`, `x`. (|((true, x, y) | (false, y, x))| {})(expr); ``` Implementation-wise, this is due to differences in how pattern bindings are lowered to MIR. - For `let pat;`, we traverse the pattern in a natural order and schedule drops for bindings [here](https://github.com/rust-lang/rust/blob/321dde12528a6baf0990ec611d33122b68c33fca/compiler/rustc_mir_build/src/builder/block.rs#L294-L303). - For anything that involves pattern-matching, we use the ordering of bindings seen by match lowering, which tests or-patterns last. `match` using the final or-pattern alternative's binding order is a detail of how match guards are currently implemented [here](https://github.com/rust-lang/rust/blob/321dde12528a6baf0990ec611d33122b68c33fca/compiler/rustc_mir_build/src/builder/matches/mod.rs#L548-L584). - Function parameters' patterns are lowered left-to-right, using the usual pattern-matching lowering for each individual parameter with a non-trivial pattern [here](https://github.com/rust-lang/rust/blob/321dde12528a6baf0990ec611d33122b68c33fca/compiler/rustc_mir_build/src/builder/mod.rs#L977-L985). If this should change, I imagine it will need a T-lang decision on what the correct behavior should be, so cc @rust-lang/lang @rustbot label: +T-compiler +T-lang +A-MIR +A-patterns +A-destructors