@@ -252,10 +252,125 @@ When used on a function in a trait implementation, the attribute does nothing.
252
252
> let _ = five();
253
253
> ```
254
254
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
+
255
369
[ Clippy ] : https://github.com/rust-lang/rust-clippy
256
370
[ _MetaListNameValueStr_ ] : attributes.html#meta-item-attribute-syntax
257
371
[ _MetaListPaths_ ] : attributes.html#meta-item-attribute-syntax
258
372
[ _MetaNameValueStr_ ] : attributes.html#meta-item-attribute-syntax
373
+ [ _MetaWord_ ] : attributes.html#meta-item-attribute-syntax
259
374
[ `Drop` ] : special-types-and-traits.html#drop
260
375
[ attributes ] : attributes.html
261
376
[ block expression ] : expressions/block-expr.html
@@ -266,10 +381,12 @@ When used on a function in a trait implementation, the attribute does nothing.
266
381
[ expression ] : expressions.html
267
382
[ external block item ] : items/external-blocks.html
268
383
[ functions ] : items/functions.html
384
+ [ `if let` ] : expressions/if-expr.html#if-let-expressions
269
385
[ impl trait ] : types/impl-trait.html
270
386
[ implementation ] : items/implementations.html
271
387
[ item ] : items.html
272
388
[ let statement ] : statements.html#let-statements
389
+ [ `match` ] : expressions/match-expr.html
273
390
[ module ] : items/modules.html
274
391
[ rustc book ] : ../rustc/lints/index.html
275
392
[ struct field ] : items/structs.html
0 commit comments