@@ -252,10 +252,125 @@ When used on a function in a trait implementation, the attribute does nothing.
252252> let _ = five();
253253> ```
254254
255+ # The `non_exhaustive ` attribute
256+
257+ The * `non_exhaustive ` attribute * is used to indicate that a type will have
258+ more fields / variants added in the future . It can be applied to
259+ [`struct `s ][struct ], [`enum `s ][enum ] and `enum ` variants .
260+
261+ The `non_exhaustive ` attribute uses the [_MetaWord_ ] syntax and thus does not
262+ take any inputs .
263+
264+ Within the defining crate , types annotated with `non_exhaustive ` behave exactly
265+ the same as if the type were not annotated with `non_exhaustive `:
266+
267+ ```rust ,ignore
268+ #[non_exhaustive]
269+ pub struct Config {
270+ pub window_width : u16 ,
271+ pub window_height : u16 ,
272+ }
273+
274+ #[non_exhaustive]
275+ pub enum Error {
276+ Message (String ),
277+ Other ,
278+ }
279+
280+ pub enum Message {
281+ #[non_exhaustive] Send { from : u32 , to : u32 , contents : String },
282+ #[non_exhaustive] Reaction (u32 ),
283+ #[non_exhaustive] Quit ,
284+ }
285+
286+ // Non-exhaustive structs can be constructed as normal within the defining crate.
287+ let config = Config { window_width : 640 , window_height : 480 };
288+
289+ // Non-exhaustive structs can be matched on exhaustively within the defining crate.
290+ if let Ok (Config { window_width , window_height }) = config {
291+ // ...
292+ }
293+
294+ // Non-exhaustive enums can be matched on exhaustively within the defining crate.
295+ match error {
296+ Error :: Message (ref s ) => { },
297+ Error :: Other => { },
298+ }
299+
300+ match message {
301+ // Non-exhaustive variants can be matched on exhaustively within the defining crate.
302+ Message :: Send { from , to , contents } => { },
303+ Message :: Reaction (type ) => { },
304+ Message :: Quit => { },
305+ }
306+ ```
307+
308+ In downstream crates, types annotated with ` non_exhaustive ` have limitations that
309+ preserve backwards compatibility when new fields/variants are added.
310+
311+ Non-exhaustive types cannot be constructed in downstream crates:
312+
313+ ``` rust,ignore
314+ // `Config`, `Error` and `Message` are types defined in an upstream crate that have been
315+ // annotated as `#[non_exhaustive]`.
316+ use upstream::{Config, Error, Message};
317+
318+ // Cannot construct an instance of `Config`, if new fields were added in
319+ // a new version of `upstream` then this would fail to compile, so it is
320+ // disallowed.
321+ let config = Config { window_width: 640, window_height: 480 };
322+
323+ // Can construct an instance of `Error`, new variants being introduced would
324+ // not result in this failing to compile.
325+ let error = Error::Message("foo".to_string());
326+
327+ // Cannot construct an instance of `Message::Send` or `Message::Reaction`,
328+ // if new fields were added in a new version of `upstream` then this would
329+ // fail to compile, so it is disallowed.
330+ let message = Message::Send { from: 0, to: 1, contents: "foo".to_string(), };
331+ let message = Message::Reaction(0);
332+
333+ // Cannot construct an instance of `Message::Quit`, if this were converted to
334+ // a tuple-variant `upstream` then this would fail to compile.
335+ let message = Message::Quit;
336+ ```
337+
338+ Non-exhaustive types cannot be used in a [ ` match ` ] /[ ` if let ` ] expression without a
339+ wildcard arm:
340+
341+ ``` rust, ignore
342+ // `Config`, `Error` and `Message` are types defined in an upstream crate that have been
343+ // annotated as `#[non_exhaustive]`.
344+ use upstream::{Config, Error, Message};
345+
346+ // Cannot match on a non-exhaustive enum without including a wildcard arm.
347+ match error {
348+ Error::Message(ref s) => { },
349+ Error::Other => { },
350+ // would compile with: `_ => {},`
351+ }
352+
353+ // Cannot match on a non-exhaustive struct without a wildcard.
354+ if let Ok(Config { window_width, window_height }) = config {
355+ // would compile with: `..`
356+ }
357+
358+ match message {
359+ // Cannot match on a non-exhaustive struct enum variant without including a wildcard.
360+ Message::Send { from, to, contents } => { },
361+ // Cannot match on a non-exhaustive tuple or unit enum variant.
362+ Message::Reaction(type) => { },
363+ Message::Quit => { },
364+ }
365+ ```
366+
367+ Non-exhaustive types are always considered inhabited in downstream crates.
368+
255369[ Clippy ] : https://github.com/rust-lang/rust-clippy
256370[ _MetaListNameValueStr_ ] : ../attributes.md#meta-item-attribute-syntax
257371[ _MetaListPaths_ ] : ../attributes.md#meta-item-attribute-syntax
258372[ _MetaNameValueStr_ ] : ../attributes.md#meta-item-attribute-syntax
373+ [ _MetaWord_ ] : ../attributes.md#meta-item-attribute-syntax
259374[ `Drop` ] : ../special-types-and-traits.md#drop
260375[ attributes ] : ../attributes.md
261376[ block expression ] : ../expressions/block-expr.md
@@ -266,10 +381,12 @@ When used on a function in a trait implementation, the attribute does nothing.
266381[ expression ] : ../expressions.md
267382[ external block item ] : ../items/external-blocks.md
268383[ functions ] : ../items/functions.md
384+ [ `if let` ] : ../expressions/if-expr.md#if-let-expressions
269385[ impl trait ] : ../types/impl-trait.md
270386[ implementation ] : ../items/implementations.md
271387[ item ] : ../items.md
272388[ let statement ] : ../statements.md#let-statements
389+ [ `match` ] : ../expressions/match-expr.md
273390[ module ] : ../items/modules.md
274391[ rustc book ] : ../../rustc/lints/index.html
275392[ struct field ] : ../items/structs.md
0 commit comments