mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
Auto merge of #10877 - obi1kenobi:adding-non-exhaustive, r=weihanglo
Document that adding `#[non_exhaustive]` on existing items is breaking. ### What does this PR try to resolve? Adding `#[non_exhaustive]` to an existing struct, enum, or variant is almost always a breaking change and requires a major version bump for semver purposes. This PR adds a section to the semver reference page that describes this and provides examples showing how `#[non_exhaustive]` can break code. ### Additional information Adding `#[non_exhaustive]` to a unit struct currently has no effect on whether that struct can be constructed in downstream crates. This is inconsistent with the behavior of `#[non_exhaustive]` on unit enum variants, which may not be constructed outside their own crate. This might be due to a similar underlying cause as: https://github.com/rust-lang/rust/issues/78586 The confusing "variant is private" error messages for non-exhaustive unit and tuple variants are a known issue tracked in: https://github.com/rust-lang/rust/issues/82788 Checking for the struct portion of this semver rule is done in: https://github.com/obi1kenobi/cargo-semver-check/pull/4
This commit is contained in:
commit
c455de990c
@ -90,6 +90,7 @@ considered incompatible.
|
|||||||
* [Major: generalizing a function to use generics with type mismatch](#fn-generalize-mismatch)
|
* [Major: generalizing a function to use generics with type mismatch](#fn-generalize-mismatch)
|
||||||
* Attributes
|
* Attributes
|
||||||
* [Major: switching from `no_std` support to requiring `std`](#attr-no-std-to-std)
|
* [Major: switching from `no_std` support to requiring `std`](#attr-no-std-to-std)
|
||||||
|
* [Major: adding `non_exhaustive` to an existing enum, variant, or struct with no private fields](#attr-adding-non-exhaustive)
|
||||||
* Tooling and environment compatibility
|
* Tooling and environment compatibility
|
||||||
* [Possibly-breaking: changing the minimum version of Rust required](#env-new-rust)
|
* [Possibly-breaking: changing the minimum version of Rust required](#env-new-rust)
|
||||||
* [Possibly-breaking: changing the platform and environment requirements](#env-change-requirements)
|
* [Possibly-breaking: changing the platform and environment requirements](#env-change-requirements)
|
||||||
@ -1115,6 +1116,89 @@ Mitigation strategies:
|
|||||||
optionally enables `std` support, and when the feature is off, the library
|
optionally enables `std` support, and when the feature is off, the library
|
||||||
can be used in a `no_std` environment.
|
can be used in a `no_std` environment.
|
||||||
|
|
||||||
|
<a id="attr-adding-non-exhaustive"></a>
|
||||||
|
### Major: adding `non_exhaustive` to an existing enum, variant, or struct with no private fields
|
||||||
|
|
||||||
|
Making items [`#[non_exhaustive]`][non_exhaustive] changes how they may
|
||||||
|
be used outside the crate where they are defined:
|
||||||
|
|
||||||
|
- Non-exhaustive structs and enum variants cannot be constructed
|
||||||
|
using [struct literal] syntax, including [functional update syntax].
|
||||||
|
- Pattern matching on non-exhaustive structs requires `..` and
|
||||||
|
matching on enums does not count towards exhaustiveness.
|
||||||
|
- Casting enum variants to their discriminant with `as` is not allowed.
|
||||||
|
|
||||||
|
Structs with private fields cannot be constructed using [struct literal] syntax
|
||||||
|
regardless of whether [`#[non_exhaustive]`][non_exhaustive] is used.
|
||||||
|
Adding [`#[non_exhaustive]`][non_exhaustive] to such a struct is not
|
||||||
|
a breaking change.
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
// MAJOR CHANGE
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// Before
|
||||||
|
pub struct Foo {
|
||||||
|
pub bar: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Bar {
|
||||||
|
X,
|
||||||
|
Y(usize),
|
||||||
|
Z { a: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Quux {
|
||||||
|
Var,
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// After
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct Foo {
|
||||||
|
pub bar: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Bar {
|
||||||
|
#[non_exhaustive]
|
||||||
|
X,
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
|
Y(usize),
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
|
Z { a: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum Quux {
|
||||||
|
Var,
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// Example usage that will break.
|
||||||
|
use updated_crate::{Bar, Foo, Quux};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo = Foo { bar: 0 }; // Error: cannot create non-exhaustive struct using struct expression
|
||||||
|
|
||||||
|
let bar_x = Bar::X; // Error: unit variant `X` is private
|
||||||
|
let bar_y = Bar::Y(0); // Error: tuple variant `Y` is private
|
||||||
|
let bar_z = Bar::Z { a: 0 }; // Error: cannot create non-exhaustive variant using struct expression
|
||||||
|
|
||||||
|
let q = Quux::Var;
|
||||||
|
match q {
|
||||||
|
Quux::Var => 0,
|
||||||
|
// Error: non-exhaustive patterns: `_` not covered
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Mitigation strategies:
|
||||||
|
* Mark structs, enums, and enum variants as
|
||||||
|
[`#[non_exhaustive]`][non_exhaustive] when first introducing them,
|
||||||
|
rather than adding [`#[non_exhaustive]`][non_exhaustive] later on.
|
||||||
|
|
||||||
## Tooling and environment compatibility
|
## Tooling and environment compatibility
|
||||||
|
|
||||||
<a id="env-new-rust"></a>
|
<a id="env-new-rust"></a>
|
||||||
@ -1393,6 +1477,7 @@ document what your commitments are.
|
|||||||
[Default]: ../../std/default/trait.Default.html
|
[Default]: ../../std/default/trait.Default.html
|
||||||
[deprecated]: ../../reference/attributes/diagnostics.html#the-deprecated-attribute
|
[deprecated]: ../../reference/attributes/diagnostics.html#the-deprecated-attribute
|
||||||
[disambiguation syntax]: ../../reference/expressions/call-expr.html#disambiguating-function-calls
|
[disambiguation syntax]: ../../reference/expressions/call-expr.html#disambiguating-function-calls
|
||||||
|
[functional update syntax]: ../../reference/expressions/struct-expr.html#functional-update-syntax
|
||||||
[inherent implementations]: ../../reference/items/implementations.html#inherent-implementations
|
[inherent implementations]: ../../reference/items/implementations.html#inherent-implementations
|
||||||
[items]: ../../reference/items.html
|
[items]: ../../reference/items.html
|
||||||
[non_exhaustive]: ../../reference/attributes/type_system.html#the-non_exhaustive-attribute
|
[non_exhaustive]: ../../reference/attributes/type_system.html#the-non_exhaustive-attribute
|
||||||
|
Loading…
x
Reference in New Issue
Block a user