Skip to content

Document which union patterns are unsafe - #2350

Draft
Jules-Bertholet wants to merge 4 commits into
rust-lang:masterfrom
Jules-Bertholet:safe-union-leaf-patterns
Draft

Jules-Bertholet wants to merge 4 commits into
rust-lang:masterfrom
Jules-Bertholet:safe-union-leaf-patterns

Conversation

@Jules-Bertholet

@Jules-Bertholet Jules-Bertholet commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

@theemathas

Copy link
Copy Markdown
Contributor

I think this kind of definition of what patterns "access" a thing could also be useful for implementing a lint for rust-lang/rust#158387 (comment). cc @Nadrieril

Comment thread src/items/unions.md
Comment thread src/items/unions.md
Comment thread src/items/unions.md
- [Reference patterns](../patterns.md#reference-patterns)
- [Non-reference patterns](../patterns.md#r-patterns.ident.binding.non-reference) matching reference values
- [Struct](../patterns.md#struct-patterns) and [tuple struct](../patterns.md#tuple-struct-patterns) patterns which correspond to an enum variant
- [Path patterns](../patterns.md#path-patterns), if the result of expanding the constant into a pattern contains one of the above, or if the expanded pattern could not have been written directly at the location where it is used due to field privacy or `#[non_exhaustive]`.

@Nadrieril Nadrieril Sep 21, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to add constant patterns there, because it should be allowed to turn a constant patter nmatch into a call to PartialEq::eq for performance. This conflicts with https://doc.rust-lang.org/reference/patterns.html?highlight=patterns#r-patterns.const.translation a bit so we conceptually are saying "unsafety checking is done before we expand constant patterns"

View changes since the review

Comment thread src/items/unions.md
}
```

`unsafe` is only required if the union field is accessed, in whole or in part, by the pattern, including any of its sub-patterns. For the purpose of this requirement, the following patterns are considered to perform an access:

@RalfJung RalfJung Oct 2, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if we add a new pattern kind and forget to add it here, then we're implicitly specifying that as being allowed? That seems like a dangerous default.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is, but on the other hand:

  • Explaining this in the negative would be a lot less clear/understandable.
  • You can't add a new pattern kind to the compiler without touching the code that implements this check.

I think we should just add a comment to visit_pat in rustc_mir_build/check_unsafety reminding people to update this list.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explaining this in the negative would be a lot less clear/understandable.

Why? isn't it something like, a pattern matching on a union field is safe only if it recursively consists exclusively of

  • array patterns
  • struct patterns
  • _ patterns
  • (add a few more maybe?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think reasoning in terms of what code doesn't do is inherently more fraught than reasoning about what it does. That's the approach we take in https://doc.rust-lang.org/reference/unsafety.html: we list all the unsafe operations, not all the operations that aren't unsafe.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the opposite is true, it's much more reliable to enumerate what is safe than what isn't.

For Rust generally this isn't a great default because most operations are safe, but when we are talking about unions it is exactly the right default IMO.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants