Skip to content

Commit d6b2e08

Browse files
committed
Add non_exhaustive to reference.
1 parent 862b669 commit d6b2e08

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

src/attributes.md

+3
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ The following is an index of all built-in attributes.
196196
- [`allow`], [`warn`], [`deny`], [`forbid`] — Alters the default lint level.
197197
- [`deprecated`] — Generates deprecation notices.
198198
- [`must_use`] — Generates a lint for unused values.
199+
- [`non_exhaustive`] — Indicate that a type will have more fields/variants
200+
added in future.
199201
- ABI, linking, symbols, and FFI
200202
- [`link`] — Specifies a native library to link with an `extern` block.
201203
- [`link_name`] — Specifies the name of the symbol for functions or statics
@@ -276,6 +278,7 @@ The following is an index of all built-in attributes.
276278
[`no_main`]: crates-and-source-files.html#the-no_main-attribute
277279
[`no_mangle`]: abi.html#the-no_mangle-attribute
278280
[`no_std`]: crates-and-source-files.html#preludes-and-no_std
281+
[`non_exhaustive`]: attributes/diagnostics.html#the-non_exhaustive-attribute
279282
[`panic_handler`]: runtime.html#the-panic_handler-attribute
280283
[`path`]: items/modules.html#the-path-attribute
281284
[`proc_macro_attribute`]: procedural-macros.html#attribute-macros

src/attributes/diagnostics.md

+117
Original file line numberDiff line numberDiff line change
@@ -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.html#meta-item-attribute-syntax
257371
[_MetaListPaths_]: attributes.html#meta-item-attribute-syntax
258372
[_MetaNameValueStr_]: attributes.html#meta-item-attribute-syntax
373+
[_MetaWord_]: attributes.html#meta-item-attribute-syntax
259374
[`Drop`]: special-types-and-traits.html#drop
260375
[attributes]: attributes.html
261376
[block expression]: expressions/block-expr.html
@@ -266,10 +381,12 @@ When used on a function in a trait implementation, the attribute does nothing.
266381
[expression]: expressions.html
267382
[external block item]: items/external-blocks.html
268383
[functions]: items/functions.html
384+
[`if let`]: expressions/if-expr.html#if-let-expressions
269385
[impl trait]: types/impl-trait.html
270386
[implementation]: items/implementations.html
271387
[item]: items.html
272388
[let statement]: statements.html#let-statements
389+
[`match`]: expressions/match-expr.html
273390
[module]: items/modules.html
274391
[rustc book]: ../rustc/lints/index.html
275392
[struct field]: items/structs.html

0 commit comments

Comments
 (0)