From d51ea538e4eddbf0e0d968484a3e980db239549c Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Fri, 3 Nov 2017 19:14:39 +0000
Subject: [PATCH 1/5] Added feature gate for RFC 2008.

---
 src/libsyntax/feature_gate.rs | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 30451ec757a9f..3996bdb819db3 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -386,6 +386,9 @@ declare_features! (
     // allow '|' at beginning of match arms (RFC 1925)
     (active, match_beginning_vert, "1.21.0", Some(44101)),
 
+    // Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008)
+    (active, non_exhaustive, "1.22.0", Some(44109)),
+
     // Copy/Clone closures (RFC 2132)
     (active, clone_closures, "1.22.0", Some(44490)),
     (active, copy_closures, "1.22.0", Some(44490)),
@@ -614,6 +617,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                              not yet settled",
                                             cfg_fn!(structural_match))),
 
+    // RFC #2008
+    ("non_exhaustive", Whitelisted, Gated(Stability::Unstable,
+                                          "non_exhaustive",
+                                          "non exhaustive is an experimental feature",
+                                          cfg_fn!(non_exhaustive))),
+
     ("plugin", CrateLevel, Gated(Stability::Unstable,
                                  "plugin",
                                  "compiler plugins are experimental \

From 6c19ebe1288c1fc6fa5d9b1c65da256eede7a77c Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Fri, 3 Nov 2017 19:15:15 +0000
Subject: [PATCH 2/5] Added tests for RFC 2008.

---
 .../feature-gate-non_exhaustive.rs            | 20 ++++++++
 .../auxiliary/enums.rs                        | 19 ++++++++
 .../auxiliary/structs.rs                      | 37 +++++++++++++++
 .../auxiliary/variants.rs                     | 18 +++++++
 .../rfc-2008-non-exhaustive/enum.rs           | 25 ++++++++++
 .../rfc-2008-non-exhaustive/structs.rs        | 47 +++++++++++++++++++
 .../rfc-2008-non-exhaustive/variants.rs       | 36 ++++++++++++++
 .../variants_create.rs                        | 27 +++++++++++
 .../auxiliary/enums.rs                        | 19 ++++++++
 .../auxiliary/structs.rs                      | 23 +++++++++
 .../auxiliary/variants.rs                     | 18 +++++++
 .../run-pass/rfc-2008-non-exhaustive/enums.rs | 31 ++++++++++++
 .../enums_same_crate.rs                       | 28 +++++++++++
 .../rfc-2008-non-exhaustive/structs.rs        | 27 +++++++++++
 .../structs_same_crate.rs                     | 40 ++++++++++++++++
 .../rfc-2008-non-exhaustive/variants.rs       | 31 ++++++++++++
 .../variants_same_crate.rs                    | 34 ++++++++++++++
 17 files changed, 480 insertions(+)
 create mode 100644 src/test/compile-fail/feature-gate-non_exhaustive.rs
 create mode 100644 src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/enums.rs
 create mode 100644 src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/structs.rs
 create mode 100644 src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/variants.rs
 create mode 100644 src/test/compile-fail/rfc-2008-non-exhaustive/enum.rs
 create mode 100644 src/test/compile-fail/rfc-2008-non-exhaustive/structs.rs
 create mode 100644 src/test/compile-fail/rfc-2008-non-exhaustive/variants.rs
 create mode 100644 src/test/compile-fail/rfc-2008-non-exhaustive/variants_create.rs
 create mode 100644 src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/enums.rs
 create mode 100644 src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/structs.rs
 create mode 100644 src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/variants.rs
 create mode 100644 src/test/run-pass/rfc-2008-non-exhaustive/enums.rs
 create mode 100644 src/test/run-pass/rfc-2008-non-exhaustive/enums_same_crate.rs
 create mode 100644 src/test/run-pass/rfc-2008-non-exhaustive/structs.rs
 create mode 100644 src/test/run-pass/rfc-2008-non-exhaustive/structs_same_crate.rs
 create mode 100644 src/test/run-pass/rfc-2008-non-exhaustive/variants.rs
 create mode 100644 src/test/run-pass/rfc-2008-non-exhaustive/variants_same_crate.rs

diff --git a/src/test/compile-fail/feature-gate-non_exhaustive.rs b/src/test/compile-fail/feature-gate-non_exhaustive.rs
new file mode 100644
index 0000000000000..d2711084a4d48
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-non_exhaustive.rs
@@ -0,0 +1,20 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//#![feature(non_exhaustive)]
+
+#[non_exhaustive] //~ERROR non exhaustive is an experimental feature (see issue #44109)
+pub enum NonExhaustiveEnum {
+    Unit,
+    Tuple(u32),
+    Struct { field: u32 }
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/enums.rs
new file mode 100644
index 0000000000000..12d1bf9ea9104
--- /dev/null
+++ b/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/enums.rs
@@ -0,0 +1,19 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "rlib"]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum NonExhaustiveEnum {
+    Unit,
+    Tuple(u32),
+    Struct { field: u32 }
+}
diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/structs.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/structs.rs
new file mode 100644
index 0000000000000..4d083cc5315aa
--- /dev/null
+++ b/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/structs.rs
@@ -0,0 +1,37 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub struct NormalStruct {
+    pub first_field: u16,
+    pub second_field: u16,
+}
+
+#[non_exhaustive]
+pub struct UnitStruct;
+
+#[non_exhaustive]
+pub struct TupleStruct(pub u16, pub u16);
+
+#[derive(Debug)]
+#[non_exhaustive]
+pub struct FunctionalRecord {
+    pub first_field: u16,
+    pub second_field: u16,
+    pub third_field: bool
+}
+
+impl Default for FunctionalRecord {
+    fn default() -> FunctionalRecord {
+        FunctionalRecord { first_field: 640, second_field: 480, third_field: false }
+    }
+}
diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/variants.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/variants.rs
new file mode 100644
index 0000000000000..d04c1073ad9b3
--- /dev/null
+++ b/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/variants.rs
@@ -0,0 +1,18 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "rlib"]
+#![feature(non_exhaustive)]
+
+pub enum NonExhaustiveVariants {
+    #[non_exhaustive] Unit,
+    #[non_exhaustive] Tuple(u32),
+    #[non_exhaustive] Struct { field: u32 }
+}
diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/enum.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/enum.rs
new file mode 100644
index 0000000000000..0c19210e4a0ed
--- /dev/null
+++ b/src/test/compile-fail/rfc-2008-non-exhaustive/enum.rs
@@ -0,0 +1,25 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:enums.rs
+extern crate enums;
+
+use enums::NonExhaustiveEnum;
+
+fn main() {
+    let enum_unit = NonExhaustiveEnum::Unit;
+
+    match enum_unit {
+        //~^ ERROR non-exhaustive patterns: `_` not covered [E0004]
+        NonExhaustiveEnum::Unit => "first",
+        NonExhaustiveEnum::Tuple(_) => "second",
+        NonExhaustiveEnum::Struct { .. } => "third"
+    };
+}
diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/structs.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/structs.rs
new file mode 100644
index 0000000000000..74c9c7c61ace8
--- /dev/null
+++ b/src/test/compile-fail/rfc-2008-non-exhaustive/structs.rs
@@ -0,0 +1,47 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:structs.rs
+extern crate structs;
+
+use structs::{NormalStruct, UnitStruct, TupleStruct, FunctionalRecord};
+
+fn main() {
+    let fr = FunctionalRecord {
+    //~^ ERROR cannot create non-exhaustive struct
+        first_field: 1920,
+        second_field: 1080,
+        ..FunctionalRecord::default()
+    };
+
+    let ns = NormalStruct { first_field: 640, second_field: 480 };
+    //~^ ERROR cannot create non-exhaustive struct
+
+    let NormalStruct { first_field, second_field } = ns;
+    //~^ ERROR `..` required with struct marked as non-exhaustive
+
+    let ts = TupleStruct(640, 480);
+    //~^ ERROR expected function, found struct `TupleStruct` [E0423]
+
+    let ts_explicit = structs::TupleStruct(640, 480);
+    //~^ ERROR tuple struct `TupleStruct` is private [E0603]
+
+    let TupleStruct { 0: first_field, 1: second_field } = ts;
+    //~^ ERROR `..` required with struct marked as non-exhaustive
+
+    let us = UnitStruct;
+    //~^ ERROR expected value, found struct `UnitStruct` [E0423]
+
+    let us_explicit = structs::UnitStruct;
+    //~^ ERROR unit struct `UnitStruct` is private [E0603]
+
+    let UnitStruct { } = us;
+    //~^ ERROR `..` required with struct marked as non-exhaustive
+}
diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/variants.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/variants.rs
new file mode 100644
index 0000000000000..d1b65ac1f3e52
--- /dev/null
+++ b/src/test/compile-fail/rfc-2008-non-exhaustive/variants.rs
@@ -0,0 +1,36 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:variants.rs
+extern crate variants;
+
+use variants::NonExhaustiveVariants;
+
+/*
+ * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
+ * variants. See issue #44109 and PR 45394.
+ */
+// ignore-test
+
+fn main() {
+    let variant_struct = NonExhaustiveVariants::Struct { field: 640 };
+    //~^ ERROR cannot create non-exhaustive variant
+
+    let variant_tuple = NonExhaustiveVariants::Tuple { 0: 640 };
+    //~^ ERROR cannot create non-exhaustive variant
+
+    match variant_struct {
+        NonExhaustiveVariants::Unit => "",
+        NonExhaustiveVariants::Tuple(fe_tpl) => "",
+        //~^ ERROR `..` required with variant marked as non-exhaustive
+        NonExhaustiveVariants::Struct { field } => ""
+        //~^ ERROR `..` required with variant marked as non-exhaustive
+    };
+}
diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/variants_create.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/variants_create.rs
new file mode 100644
index 0000000000000..f4e4b1bb84b8b
--- /dev/null
+++ b/src/test/compile-fail/rfc-2008-non-exhaustive/variants_create.rs
@@ -0,0 +1,27 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(non_exhaustive)]
+
+/*
+ * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
+ * variants. See issue #44109 and PR 45394.
+ */
+
+pub enum NonExhaustiveVariants {
+    #[non_exhaustive] Unit,
+    //~^ ERROR #[non_exhaustive] is not yet supported on variants
+    #[non_exhaustive] Tuple(u32),
+    //~^ ERROR #[non_exhaustive] is not yet supported on variants
+    #[non_exhaustive] Struct { field: u32 }
+    //~^ ERROR #[non_exhaustive] is not yet supported on variants
+}
+
+fn main() { }
diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/enums.rs
new file mode 100644
index 0000000000000..12d1bf9ea9104
--- /dev/null
+++ b/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/enums.rs
@@ -0,0 +1,19 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "rlib"]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum NonExhaustiveEnum {
+    Unit,
+    Tuple(u32),
+    Struct { field: u32 }
+}
diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/structs.rs b/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/structs.rs
new file mode 100644
index 0000000000000..a2c6f8c05e2c9
--- /dev/null
+++ b/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/structs.rs
@@ -0,0 +1,23 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub struct NormalStruct {
+    pub first_field: u16,
+    pub second_field: u16,
+}
+
+#[non_exhaustive]
+pub struct UnitStruct;
+
+#[non_exhaustive]
+pub struct TupleStruct (pub u16, pub u16);
diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/variants.rs b/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/variants.rs
new file mode 100644
index 0000000000000..d04c1073ad9b3
--- /dev/null
+++ b/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/variants.rs
@@ -0,0 +1,18 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "rlib"]
+#![feature(non_exhaustive)]
+
+pub enum NonExhaustiveVariants {
+    #[non_exhaustive] Unit,
+    #[non_exhaustive] Tuple(u32),
+    #[non_exhaustive] Struct { field: u32 }
+}
diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/enums.rs b/src/test/run-pass/rfc-2008-non-exhaustive/enums.rs
new file mode 100644
index 0000000000000..aaee70d6d80ce
--- /dev/null
+++ b/src/test/run-pass/rfc-2008-non-exhaustive/enums.rs
@@ -0,0 +1,31 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:enums.rs
+extern crate enums;
+
+use enums::NonExhaustiveEnum;
+
+fn main() {
+    let enum_unit = NonExhaustiveEnum::Unit;
+
+    match enum_unit {
+        NonExhaustiveEnum::Unit => 1,
+        NonExhaustiveEnum::Tuple(_) => 2,
+        // This particular arm tests that a enum marked as non-exhaustive
+        // will not error if its variants are matched exhaustively.
+        NonExhaustiveEnum::Struct { field } => field,
+        _ => 0 // no error with wildcard
+    };
+
+    match enum_unit {
+        _ => "no error with only wildcard"
+    };
+}
diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/enums_same_crate.rs b/src/test/run-pass/rfc-2008-non-exhaustive/enums_same_crate.rs
new file mode 100644
index 0000000000000..8f1ba364b0e2b
--- /dev/null
+++ b/src/test/run-pass/rfc-2008-non-exhaustive/enums_same_crate.rs
@@ -0,0 +1,28 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum NonExhaustiveEnum {
+    Unit,
+    Tuple(u32),
+    Struct { field: u32 }
+}
+
+fn main() {
+    let enum_unit = NonExhaustiveEnum::Unit;
+
+    match enum_unit {
+        NonExhaustiveEnum::Unit => "first",
+        NonExhaustiveEnum::Tuple(_) => "second",
+        NonExhaustiveEnum::Struct { .. } => "third",
+    };
+}
diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/structs.rs b/src/test/run-pass/rfc-2008-non-exhaustive/structs.rs
new file mode 100644
index 0000000000000..bb65e10da27bf
--- /dev/null
+++ b/src/test/run-pass/rfc-2008-non-exhaustive/structs.rs
@@ -0,0 +1,27 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:structs.rs
+extern crate structs;
+
+use structs::{NormalStruct, UnitStruct, TupleStruct};
+
+// We only test matching here as we cannot create non-exhaustive
+// structs from another crate. ie. they'll never pass in run-pass tests.
+
+fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) {
+    let NormalStruct { first_field, second_field, .. } = ns;
+
+    let TupleStruct { 0: first, 1: second, .. } = ts;
+
+    let UnitStruct { .. } = us;
+}
+
+fn main() { }
diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/structs_same_crate.rs b/src/test/run-pass/rfc-2008-non-exhaustive/structs_same_crate.rs
new file mode 100644
index 0000000000000..175782f10fc91
--- /dev/null
+++ b/src/test/run-pass/rfc-2008-non-exhaustive/structs_same_crate.rs
@@ -0,0 +1,40 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub struct NormalStruct {
+    pub first_field: u16,
+    pub second_field: u16,
+}
+
+#[non_exhaustive]
+pub struct UnitStruct;
+
+#[non_exhaustive]
+pub struct TupleStruct (pub u16, pub u16);
+
+fn main() {
+    let ns = NormalStruct { first_field: 640, second_field: 480 };
+
+    let NormalStruct { first_field, second_field } = ns;
+
+    let ts = TupleStruct { 0: 340, 1: 480 };
+    let ts_constructor = TupleStruct(340, 480);
+
+    let TupleStruct { 0: first, 1: second } = ts;
+    let TupleStruct(first, second) = ts_constructor;
+
+    let us = UnitStruct {};
+    let us_constructor = UnitStruct;
+
+    let UnitStruct { } = us;
+}
diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/variants.rs b/src/test/run-pass/rfc-2008-non-exhaustive/variants.rs
new file mode 100644
index 0000000000000..2658c59a69985
--- /dev/null
+++ b/src/test/run-pass/rfc-2008-non-exhaustive/variants.rs
@@ -0,0 +1,31 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:variants.rs
+extern crate variants;
+
+use variants::NonExhaustiveVariants;
+
+/*
+ * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
+ * variants. See issue #44109 and PR 45394.
+ */
+// ignore-test
+
+fn main() {
+    let variant_tuple = NonExhaustiveVariants::Tuple { 0: 340 };
+    let variant_struct = NonExhaustiveVariants::Struct { field: 340 };
+
+    match variant_struct {
+        NonExhaustiveVariants::Unit => "",
+        NonExhaustiveVariants::Struct { field, .. } => "",
+        NonExhaustiveVariants::Tuple(fe_tpl, ..) => ""
+    };
+}
diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/variants_same_crate.rs b/src/test/run-pass/rfc-2008-non-exhaustive/variants_same_crate.rs
new file mode 100644
index 0000000000000..a1c376c17985d
--- /dev/null
+++ b/src/test/run-pass/rfc-2008-non-exhaustive/variants_same_crate.rs
@@ -0,0 +1,34 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(non_exhaustive)]
+
+/*
+ * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
+ * variants. See issue #44109 and PR 45394.
+ */
+// ignore-test
+
+pub enum NonExhaustiveVariants {
+    #[non_exhaustive] Unit,
+    #[non_exhaustive] Tuple(u32),
+    #[non_exhaustive] Struct { field: u32 }
+}
+
+fn main() {
+    let variant_tuple = NonExhaustiveVariants::Tuple(340);
+    let variant_struct = NonExhaustiveVariants::Struct { field: 340 };
+
+    match variant_tuple {
+        NonExhaustiveVariants::Unit => "",
+        NonExhaustiveVariants::Tuple(fe_tpl) => "",
+        NonExhaustiveVariants::Struct { field } => ""
+    };
+}

From 059eccb07f35cd3dd1119d116c593b247752d682 Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Fri, 3 Nov 2017 19:17:54 +0000
Subject: [PATCH 3/5] Implemented RFC 2008 for enums (not including variants)
 and structs.

---
 src/librustc/ty/mod.rs                      | 14 ++++
 src/librustc_const_eval/_match.rs           | 73 +++++++++++++++++++--
 src/librustc_metadata/encoder.rs            |  9 ++-
 src/librustc_passes/ast_validation.rs       | 10 +++
 src/librustc_privacy/lib.rs                 | 10 +++
 src/librustc_resolve/build_reduced_graph.rs | 16 ++++-
 src/librustc_typeck/check/_match.rs         | 12 +++-
 src/librustc_typeck/check/mod.rs            |  9 +++
 src/librustc_typeck/diagnostics.rs          | 59 +++++++++++++++++
 9 files changed, 203 insertions(+), 9 deletions(-)

diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index ee1668d6fa25f..861238c10ba57 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1326,6 +1326,12 @@ bitflags! {
         const IS_FUNDAMENTAL      = 1 << 2;
         const IS_UNION            = 1 << 3;
         const IS_BOX              = 1 << 4;
+        /// Indicates whether this abstract data type will be expanded on in future (new
+        /// fields/variants) and as such, whether downstream crates must match exhaustively on the
+        /// fields/variants of this data type.
+        ///
+        /// See RFC 2008 (https://github.com/rust-lang/rfcs/pull/2008).
+        const IS_NON_EXHAUSTIVE   = 1 << 5;
     }
 }
 
@@ -1526,6 +1532,9 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         if Some(did) == tcx.lang_items().owned_box() {
             flags = flags | AdtFlags::IS_BOX;
         }
+        if tcx.has_attr(did, "non_exhaustive") {
+            flags = flags | AdtFlags::IS_NON_EXHAUSTIVE;
+        }
         match kind {
             AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM,
             AdtKind::Union => flags = flags | AdtFlags::IS_UNION,
@@ -1554,6 +1563,11 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         self.flags.intersects(AdtFlags::IS_ENUM)
     }
 
+    #[inline]
+    pub fn is_non_exhaustive(&self) -> bool {
+        self.flags.intersects(AdtFlags::IS_NON_EXHAUSTIVE)
+    }
+
     /// Returns the kind of the ADT - Struct or Enum.
     #[inline]
     pub fn adt_kind(&self) -> AdtKind {
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index 08f3b0a4c5fd1..6ebe3c679667f 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -208,6 +208,20 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
         }
     }
 
+    fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
+        match ty.sty {
+            ty::TyAdt(adt_def, ..) => adt_def.is_enum() && adt_def.is_non_exhaustive(),
+            _ => false,
+        }
+    }
+
+    fn is_local(&self, ty: Ty<'tcx>) -> bool {
+        match ty.sty {
+            ty::TyAdt(adt_def, ..) => adt_def.did.is_local(),
+            _ => false,
+        }
+    }
+
     fn is_variant_uninhabited(&self,
                               variant: &'tcx ty::VariantDef,
                               substs: &'tcx ty::subst::Substs<'tcx>)
@@ -628,9 +642,16 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
 
         let is_privately_empty =
             all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
-        debug!("missing_ctors={:?} is_privately_empty={:?}", missing_ctors,
-               is_privately_empty);
-        if missing_ctors.is_empty() && !is_privately_empty {
+        let is_declared_nonexhaustive =
+            cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
+        debug!("missing_ctors={:?} is_privately_empty={:?} is_declared_nonexhaustive={:?}",
+               missing_ctors, is_privately_empty, is_declared_nonexhaustive);
+
+        // For privately empty and non-exhaustive enums, we work as if there were an "extra"
+        // `_` constructor for the type, so we can never match over all constructors.
+        let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive;
+
+        if missing_ctors.is_empty() && !is_non_exhaustive {
             all_ctors.into_iter().map(|c| {
                 is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
             }).find(|result| result.is_useful()).unwrap_or(NotUseful)
@@ -645,7 +666,51 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
             match is_useful(cx, &matrix, &v[1..], witness) {
                 UsefulWithWitness(pats) => {
                     let cx = &*cx;
-                    let new_witnesses = if used_ctors.is_empty() {
+                    // In this case, there's at least one "free"
+                    // constructor that is only matched against by
+                    // wildcard patterns.
+                    //
+                    // There are 2 ways we can report a witness here.
+                    // Commonly, we can report all the "free"
+                    // constructors as witnesses, e.g. if we have:
+                    //
+                    // ```
+                    //     enum Direction { N, S, E, W }
+                    //     let Direction::N = ...;
+                    // ```
+                    //
+                    // we can report 3 witnesses: `S`, `E`, and `W`.
+                    //
+                    // However, there are 2 cases where we don't want
+                    // to do this and instead report a single `_` witness:
+                    //
+                    // 1) If the user is matching against a non-exhaustive
+                    // enum, there is no point in enumerating all possible
+                    // variants, because the user can't actually match
+                    // against them himself, e.g. in an example like:
+                    // ```
+                    //     let err: io::ErrorKind = ...;
+                    //     match err {
+                    //         io::ErrorKind::NotFound => {},
+                    //     }
+                    // ```
+                    // we don't want to show every possible IO error,
+                    // but instead have `_` as the witness (this is
+                    // actually *required* if the user specified *all*
+                    // IO errors, but is probably what we want in every
+                    // case).
+                    //
+                    // 2) If the user didn't actually specify a constructor
+                    // in this arm, e.g. in
+                    // ```
+                    //     let x: (Direction, Direction, bool) = ...;
+                    //     let (_, _, false) = x;
+                    // ```
+                    // we don't want to show all 16 possible witnesses
+                    // `(<direction-1>, <direction-2>, true)` - we are
+                    // satisfied with `(_, _, true)`. In this case,
+                    // `used_ctors` is empty.
+                    let new_witnesses = if is_non_exhaustive || used_ctors.is_empty() {
                         // All constructors are unused. Add wild patterns
                         // rather than each individual constructor
                         pats.into_iter().map(|mut witness| {
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 725d6d8fad0e0..458eec3724459 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -584,7 +584,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
     fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<'tcx> {
         debug!("IsolatedEncoder::encode_struct_ctor({:?})", def_id);
         let tcx = self.tcx;
-        let variant = tcx.adt_def(adt_def_id).struct_variant();
+        let adt_def = tcx.adt_def(adt_def_id);
+        let variant = adt_def.struct_variant();
 
         let data = VariantData {
             ctor_kind: variant.ctor_kind,
@@ -606,6 +607,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
             }
         }
 
+        // If the structure is marked as non_exhaustive then lower the visibility
+        // to within the crate.
+        if adt_def.is_non_exhaustive() && ctor_vis == ty::Visibility::Public {
+            ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
+        }
+
         let repr_options = get_repr_options(&tcx, adt_def_id);
 
         Entry {
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index e44f3f3982491..71630de6aa834 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -42,6 +42,15 @@ impl<'a> AstValidator<'a> {
         }
     }
 
+    fn invalid_non_exhaustive_attribute(&self, variant: &Variant) {
+        let has_non_exhaustive = variant.node.attrs.iter()
+            .any(|attr| attr.check_name("non_exhaustive"));
+        if has_non_exhaustive {
+            self.err_handler().span_err(variant.span,
+                                        "#[non_exhaustive] is not yet supported on variants");
+        }
+    }
+
     fn invalid_visibility(&self, vis: &Visibility, span: Span, note: Option<&str>) {
         if vis != &Visibility::Inherited {
             let mut err = struct_span_err!(self.session,
@@ -224,6 +233,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             ItemKind::Enum(ref def, _) => {
                 for variant in &def.variants {
+                    self.invalid_non_exhaustive_attribute(variant);
                     for field in variant.node.data.fields() {
                         self.invalid_visibility(&field.vis, field.span, None);
                     }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 3beba03ee1401..cc3a923f62c11 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -627,6 +627,16 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
                                 ctor_vis = field_vis;
                             }
                         }
+
+                        // If the structure is marked as non_exhaustive then lower the
+                        // visibility to within the crate.
+                        let struct_def_id = self.tcx.hir.get_parent_did(node_id);
+                        let adt_def = self.tcx.adt_def(struct_def_id);
+                        if adt_def.is_non_exhaustive() && ctor_vis == ty::Visibility::Public {
+                            ctor_vis = ty::Visibility::Restricted(
+                                DefId::local(CRATE_DEF_INDEX));
+                        }
+
                         return ctor_vis;
                     }
                     node => bug!("unexpected node kind: {:?}", node)
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 880b370c7f66b..b2866a42c426a 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -338,11 +338,22 @@ impl<'a> Resolver<'a> {
             // These items live in both the type and value namespaces.
             ItemKind::Struct(ref struct_def, _) => {
                 // Define a name in the type namespace.
-                let def = Def::Struct(self.definitions.local_def_id(item.id));
+                let def_id = self.definitions.local_def_id(item.id);
+                let def = Def::Struct(def_id);
                 self.define(parent, ident, TypeNS, (def, vis, sp, expansion));
 
-                // Record field names for error reporting.
                 let mut ctor_vis = vis;
+
+                let has_non_exhaustive = item.attrs.iter()
+                    .any(|item| item.check_name("non_exhaustive"));
+
+                // If the structure is marked as non_exhaustive then lower the visibility
+                // to within the crate.
+                if has_non_exhaustive && vis == ty::Visibility::Public {
+                    ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
+                }
+
+                // Record field names for error reporting.
                 let field_names = struct_def.fields().iter().filter_map(|field| {
                     let field_vis = self.resolve_visibility(&field.vis);
                     if ctor_vis.is_at_least(field_vis, &*self) {
@@ -414,6 +425,7 @@ impl<'a> Resolver<'a> {
         // value namespace, they are reserved for possible future use.
         let ctor_kind = CtorKind::from_ast(&variant.node.data);
         let ctor_def = Def::VariantCtor(def_id, ctor_kind);
+
         self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion));
     }
 
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index e25f7d796689d..272f13b28030e 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -825,10 +825,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                def_bm: ty::BindingMode) {
         let tcx = self.tcx;
 
-        let (substs, kind_name) = match adt_ty.sty {
-            ty::TyAdt(adt, substs) => (substs, adt.variant_descr()),
+        let (substs, adt) = match adt_ty.sty {
+            ty::TyAdt(adt, substs) => (substs, adt),
             _ => span_bug!(span, "struct pattern is not an ADT")
         };
+        let kind_name = adt.variant_descr();
 
         // Index the struct fields' types.
         let field_map = variant.fields
@@ -882,6 +883,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.check_pat_walk(&field.pat, field_ty, def_bm, true);
         }
 
+        // Require `..` if struct has non_exhaustive attribute.
+        if adt.is_struct() && adt.is_non_exhaustive() && !adt.did.is_local() && !etc {
+            span_err!(tcx.sess, span, E0638,
+                      "`..` required with {} marked as non-exhaustive",
+                      kind_name);
+        }
+
         // Report an error if incorrect number of the fields were specified.
         if kind_name == "union" {
             if fields.len() != 1 {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d942c1176aa69..82d59ecfc92cf 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3448,6 +3448,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             hir::QPath::TypeRelative(ref qself, _) => qself.span
         };
 
+        // Prohibit struct expressions when non exhaustive flag is set.
+        if let ty::TyAdt(adt, _) = struct_ty.sty {
+            if !adt.did.is_local() && adt.is_non_exhaustive() {
+                span_err!(self.tcx.sess, expr.span, E0639,
+                          "cannot create non-exhaustive {} using struct expression",
+                          adt.variant_descr());
+            }
+        }
+
         self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span, variant, fields,
                                       base_expr.is_none());
         if let &Some(ref base_expr) = base_expr {
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 594cd0878cbfb..0f273d1460335 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4606,6 +4606,65 @@ foo.method(); // Ok!
 ```
 "##,
 
+E0638: r##"
+This error indicates that the struct or enum must be matched non-exhaustively
+as it has been marked as `non_exhaustive`.
+
+When applied within a crate, downstream users of the crate will need to use the
+`_` pattern when matching enums and use the `..` pattern when matching structs.
+
+For example, in the below example, since the enum is marked as
+`non_exhaustive`, it is required that downstream crates match non-exhaustively
+on it.
+
+```rust,ignore (pseudo-Rust)
+use std::error::Error as StdError;
+
+#[non_exhaustive] pub enum Error {
+   Message(String),
+   Other,
+}
+
+impl StdError for Error {
+   fn description(&self) -> &str {
+        // This will not error, despite being marked as non_exhaustive, as this
+        // enum is defined within the current crate, it can be matched
+        // exhaustively.
+        match *self {
+           Message(ref s) => s,
+           Other => "other or unknown error",
+        }
+   }
+}
+```
+
+An example of matching non-exhaustively on the above enum is provided below:
+
+```rust,ignore (pseudo-Rust)
+use mycrate::Error;
+
+// This will not error as the non_exhaustive Error enum has been matched with a
+// wildcard.
+match error {
+   Message(ref s) => ...,
+   Other => ...,
+   _ => ...,
+}
+```
+
+Similarly, for structs, match with `..` to avoid this error.
+"##,
+
+E0639: r##"
+This error indicates that the struct or enum cannot be instantiated from
+outside of the defining crate as it has been marked as `non_exhaustive` and as
+such more fields/variants may be added in future that could cause adverse side
+effects for this code.
+
+It is recommended that you look for a `new` function or equivalent in the
+crate's documentation.
+"##,
+
 }
 
 register_diagnostics! {

From d3babe5eaa073b93c25529831ac8afb37f47c412 Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Fri, 3 Nov 2017 19:18:11 +0000
Subject: [PATCH 4/5] Added page to unstable book.

---
 .../src/language-features/non-exhaustive.md   | 75 +++++++++++++++++++
 1 file changed, 75 insertions(+)
 create mode 100644 src/doc/unstable-book/src/language-features/non-exhaustive.md

diff --git a/src/doc/unstable-book/src/language-features/non-exhaustive.md b/src/doc/unstable-book/src/language-features/non-exhaustive.md
new file mode 100644
index 0000000000000..f9840e1b83f2b
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/non-exhaustive.md
@@ -0,0 +1,75 @@
+# `non_exhaustive`
+
+The tracking issue for this feature is: [#44109]
+
+[#44109]: https://github.com/rust-lang/rust/issues/44109
+
+------------------------
+
+The `non_exhaustive` gate allows you to use the `#[non_exhaustive]` attribute
+on structs and enums. When applied within a crate, users of the crate will need
+to use the `_` pattern when matching enums and use the `..` pattern when
+matching structs. Structs marked as `non_exhaustive` will not be able to be
+created normally outside of the defining crate. This is demonstrated below:
+
+```rust,ignore (pseudo-Rust)
+use std::error::Error as StdError;
+
+#[non_exhaustive]
+pub enum Error {
+    Message(String),
+    Other,
+}
+impl StdError for Error {
+    fn description(&self) -> &str {
+        // This will not error, despite being marked as non_exhaustive, as this
+        // enum is defined within the current crate, it can be matched
+        // exhaustively.
+        match *self {
+            Message(ref s) => s,
+            Other => "other or unknown error",
+        }
+    }
+}
+```
+
+```rust,ignore (pseudo-Rust)
+use mycrate::Error;
+
+// This will not error as the non_exhaustive Error enum has been matched with
+// a wildcard.
+match error {
+    Message(ref s) => ...,
+    Other => ...,
+    _ => ...,
+}
+```
+
+```rust,ignore (pseudo-Rust)
+#[non_exhaustive]
+pub struct Config {
+    pub window_width: u16,
+    pub window_height: u16,
+}
+
+// We can create structs as normal within the defining crate when marked as
+// non_exhaustive.
+let config = Config { window_width: 640, window_height: 480 };
+
+// We can match structs exhaustively when within the defining crate.
+if let Ok(Config { window_width, window_height }) = load_config() {
+    // ...
+}
+```
+
+```rust,ignore (pseudo-Rust)
+use mycrate::Config;
+
+// We cannot create a struct like normal if it has been marked as
+// non_exhaustive.
+let config = Config { window_width: 640, window_height: 480 };
+// By adding the `..` we can match the config as below outside of the crate
+// when marked non_exhaustive.
+let &Config { window_width, window_height, .. } = config;
+```
+

From 86c62d02eebb037faf7c0752a9c472181e5608cb Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Sat, 4 Nov 2017 18:01:35 +0000
Subject: [PATCH 5/5] Ignoring pretty print for test due to #37199

---
 src/test/run-pass/rfc-2008-non-exhaustive/enums.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/enums.rs b/src/test/run-pass/rfc-2008-non-exhaustive/enums.rs
index aaee70d6d80ce..9d41eca8fe5d2 100644
--- a/src/test/run-pass/rfc-2008-non-exhaustive/enums.rs
+++ b/src/test/run-pass/rfc-2008-non-exhaustive/enums.rs
@@ -11,6 +11,8 @@
 // aux-build:enums.rs
 extern crate enums;
 
+// ignore-pretty issue #37199
+
 use enums::NonExhaustiveEnum;
 
 fn main() {