From 59be332a1b3b190ec5dfdb6768e80f9d312a0c6b Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Fri, 29 Jul 2016 23:47:55 +0300
Subject: [PATCH 1/2] Remove restrictions from tuple structs/variants

Hard errors are turned into feature gates
---
 src/librustc_passes/ast_validation.rs         | 21 ------
 src/librustc_typeck/check/mod.rs              | 27 +++++--
 src/libsyntax/feature_gate.rs                 | 24 +++++-
 src/test/compile-fail/E0071.rs                |  6 +-
 .../compile-fail/auxiliary/empty-struct.rs    |  4 +
 .../compile-fail/empty-struct-braces-pat-2.rs | 15 ++--
 .../compile-fail/empty-struct-braces-pat-3.rs | 15 ++--
 .../compile-fail/empty-struct-tuple-pat.rs    | 47 ++++++++++++
 ...unit-pat.rs => empty-struct-unit-pat-1.rs} | 18 +----
 .../compile-fail/empty-struct-unit-pat-2.rs   | 47 ++++++++++++
 .../feature-gate-relaxed-adts-2.rs            | 27 +++++++
 .../feature-gate-relaxed-adts.rs}             | 19 +++--
 src/test/compile-fail/issue-12560-1.rs        | 25 -------
 src/test/compile-fail/issue-12560-2.rs        | 29 --------
 src/test/compile-fail/issue-16819.rs          |  4 +-
 src/test/compile-fail/issue-17800.rs          |  5 +-
 src/test/compile-fail/issue-27831.rs          | 34 ---------
 src/test/compile-fail/issue-4736.rs           |  4 +-
 .../compile-fail/struct-no-fields-enumlike.rs | 13 ----
 src/test/run-pass/auxiliary/empty-struct.rs   |  4 +
 .../run-pass/empty-struct-braces-gate-2.rs    | 46 ------------
 src/test/run-pass/empty-struct-braces.rs      | 74 +++++++++++++++++++
 22 files changed, 284 insertions(+), 224 deletions(-)
 create mode 100644 src/test/compile-fail/empty-struct-tuple-pat.rs
 rename src/test/compile-fail/{empty-struct-unit-pat.rs => empty-struct-unit-pat-1.rs} (71%)
 create mode 100644 src/test/compile-fail/empty-struct-unit-pat-2.rs
 create mode 100644 src/test/compile-fail/feature-gate-relaxed-adts-2.rs
 rename src/test/{run-pass/empty-struct-braces-gate-1.rs => compile-fail/feature-gate-relaxed-adts.rs} (50%)
 delete mode 100644 src/test/compile-fail/issue-12560-1.rs
 delete mode 100644 src/test/compile-fail/issue-12560-2.rs
 delete mode 100644 src/test/compile-fail/issue-27831.rs
 delete mode 100644 src/test/compile-fail/struct-no-fields-enumlike.rs
 delete mode 100644 src/test/run-pass/empty-struct-braces-gate-2.rs

diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 341c9d820e6..1e8da29ee74 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -197,27 +197,6 @@ impl<'a> Visitor for AstValidator<'a> {
         visit::walk_foreign_item(self, fi)
     }
 
-    fn visit_variant_data(&mut self,
-                          vdata: &VariantData,
-                          _: Ident,
-                          _: &Generics,
-                          _: NodeId,
-                          span: Span) {
-        if vdata.fields().is_empty() {
-            if vdata.is_tuple() {
-                self.err_handler()
-                    .struct_span_err(span,
-                                     "empty tuple structs and enum variants are not allowed, use \
-                                      unit structs and enum variants instead")
-                    .span_help(span,
-                               "remove trailing `()` to make a unit struct or unit enum variant")
-                    .emit();
-            }
-        }
-
-        visit::walk_struct_def(self, vdata)
-    }
-
     fn visit_vis(&mut self, vis: &Visibility) {
         match *vis {
             Visibility::Restricted { ref path, .. } => {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c2c93161ce7..0c8e6d990a6 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -116,6 +116,7 @@ use syntax::ast;
 use syntax::attr;
 use syntax::attr::AttrMetaMethods;
 use syntax::codemap::{self, Spanned};
+use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::parse::token::{self, InternedString, keywords};
 use syntax::ptr::P;
 use syntax::util::lev_distance::find_best_match_for_name;
@@ -1700,7 +1701,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                  node_id: ast::NodeId)
                                  -> Ty<'tcx> {
         debug!("instantiate_type_path(did={:?}, path={:?})", did, path);
-        let type_scheme = self.tcx.lookup_item_type(did);
+        let mut type_scheme = self.tcx.lookup_item_type(did);
+        if type_scheme.ty.is_fn() {
+            // Tuple variants have fn type even in type namespace, extract true variant type from it
+            let fn_ret = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap().unwrap();
+            type_scheme = ty::TypeScheme { ty: fn_ret, generics: type_scheme.generics }
+        }
         let type_predicates = self.tcx.lookup_predicates(did);
         let substs = AstConv::ast_path_substs_for_ty(self, self,
                                                      path.span,
@@ -3244,19 +3250,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             _ => None
         };
-        if variant.is_none() || variant.unwrap().kind == ty::VariantKind::Tuple {
-            // Reject tuple structs for now, braced and unit structs are allowed.
+
+        if let Some(variant) = variant {
+            if variant.kind == ty::VariantKind::Tuple &&
+                    !self.tcx.sess.features.borrow().relaxed_adts {
+                emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic,
+                                 "relaxed_adts", span, GateIssue::Language,
+                                 "tuple structs and variants in struct patterns are unstable");
+            }
+            let ty = self.instantiate_type_path(def.def_id(), path, node_id);
+            Some((variant, ty))
+        } else {
             struct_span_err!(self.tcx.sess, path.span, E0071,
                              "`{}` does not name a struct or a struct variant",
                              pprust::path_to_string(path))
                 .span_label(path.span, &format!("not a struct"))
                 .emit();
-
-            return None;
+            None
         }
-
-        let ty = self.instantiate_type_path(def.def_id(), path, node_id);
-        Some((variant.unwrap(), ty))
     }
 
     fn check_expr_struct(&self,
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index f550e7d2a05..ad52184a6dc 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -280,7 +280,11 @@ declare_features! (
     (active, dotdot_in_tuple_patterns, "1.10.0", Some(33627)),
 
     // Allows `impl Trait` in function return types.
-    (active, conservative_impl_trait, "1.12.0", Some(34511))
+    (active, conservative_impl_trait, "1.12.0", Some(34511)),
+
+    // Allows tuple structs and variants in more contexts,
+    // Permits numeric fields in struct expressions and patterns.
+    (active, relaxed_adts, "1.12.0", Some(35626))
 );
 
 declare_features! (
@@ -1022,9 +1026,8 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
             }
             PatKind::TupleStruct(_, ref fields, ddpos)
                     if ddpos.is_none() && fields.is_empty() => {
-                self.context.span_handler.struct_span_err(pattern.span,
-                                                          "nullary enum variants are written with \
-                                                           no trailing `( )`").emit();
+                gate_feature_post!(&self, relaxed_adts, pattern.span,
+                                   "empty tuple structs patterns are unstable");
             }
             _ => {}
         }
@@ -1107,6 +1110,19 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
         visit::walk_impl_item(self, ii);
     }
 
+    fn visit_variant_data(&mut self, vdata: &ast::VariantData, _: ast::Ident,
+                          _: &ast::Generics, _: NodeId, span: Span) {
+        if vdata.fields().is_empty() {
+            if vdata.is_tuple() {
+                gate_feature_post!(&self, relaxed_adts, span,
+                                   "empty tuple structs and enum variants are unstable, \
+                                    use unit structs and enum variants instead");
+            }
+        }
+
+        visit::walk_struct_def(self, vdata)
+    }
+
     fn visit_vis(&mut self, vis: &ast::Visibility) {
         let span = match *vis {
             ast::Visibility::Crate(span) => span,
diff --git a/src/test/compile-fail/E0071.rs b/src/test/compile-fail/E0071.rs
index 6f0e55efffc..c13ba7bf136 100644
--- a/src/test/compile-fail/E0071.rs
+++ b/src/test/compile-fail/E0071.rs
@@ -8,11 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-enum Foo { FirstValue(i32) }
+enum Foo {}
 
 fn main() {
-    let u = Foo::FirstValue { value: 0 };
-    //~^ ERROR `Foo::FirstValue` does not name a struct or a struct variant [E0071]
+    let u = Foo { value: 0 };
+    //~^ ERROR `Foo` does not name a struct or a struct variant [E0071]
     //~| NOTE not a struct
 
     let t = u32 { value: 4 };
diff --git a/src/test/compile-fail/auxiliary/empty-struct.rs b/src/test/compile-fail/auxiliary/empty-struct.rs
index 22f65c2b0d8..dcbb0ce178b 100644
--- a/src/test/compile-fail/auxiliary/empty-struct.rs
+++ b/src/test/compile-fail/auxiliary/empty-struct.rs
@@ -8,10 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(relaxed_adts)]
+
 pub struct XEmpty1 {}
 pub struct XEmpty2;
+pub struct XEmpty6();
 
 pub enum XE {
     XEmpty3 {},
     XEmpty4,
+    XEmpty5(),
 }
diff --git a/src/test/compile-fail/empty-struct-braces-pat-2.rs b/src/test/compile-fail/empty-struct-braces-pat-2.rs
index 0522a654a85..52481517ce7 100644
--- a/src/test/compile-fail/empty-struct-braces-pat-2.rs
+++ b/src/test/compile-fail/empty-struct-braces-pat-2.rs
@@ -12,6 +12,8 @@
 
 // aux-build:empty-struct.rs
 
+#![feature(relaxed_adts)]
+
 extern crate empty_struct;
 use empty_struct::*;
 
@@ -21,13 +23,12 @@ fn main() {
     let e1 = Empty1 {};
     let xe1 = XEmpty1 {};
 
-    // Rejected by parser as yet
-    // match e1 {
-    //     Empty1() => () // ERROR unresolved enum variant, struct or const `Empty1`
-    // }
-    // match xe1 {
-    //     XEmpty1() => () // ERROR unresolved enum variant, struct or const `XEmpty1`
-    // }
+    match e1 {
+        Empty1() => () //~ ERROR unresolved variant or struct `Empty1`
+    }
+    match xe1 {
+        XEmpty1() => () //~ ERROR unresolved variant or struct `XEmpty1`
+    }
     match e1 {
         Empty1(..) => () //~ ERROR unresolved variant or struct `Empty1`
     }
diff --git a/src/test/compile-fail/empty-struct-braces-pat-3.rs b/src/test/compile-fail/empty-struct-braces-pat-3.rs
index 88249fc422f..cb859fe7501 100644
--- a/src/test/compile-fail/empty-struct-braces-pat-3.rs
+++ b/src/test/compile-fail/empty-struct-braces-pat-3.rs
@@ -12,6 +12,8 @@
 
 // aux-build:empty-struct.rs
 
+#![feature(relaxed_adts)]
+
 extern crate empty_struct;
 use empty_struct::*;
 
@@ -23,13 +25,12 @@ fn main() {
     let e3 = E::Empty3 {};
     let xe3 = XE::XEmpty3 {};
 
-    // Rejected by parser as yet
-    // match e3 {
-    //     E::Empty3() => () // ERROR `E::Empty3` does not name a tuple variant or a tuple struct
-    // }
-    // match xe3 {
-    //     E::Empty3() => () // ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct
-    // }
+    match e3 {
+        E::Empty3() => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
+    }
+    match xe3 {
+        XE::XEmpty3() => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct
+    }
     match e3 {
         E::Empty3(..) => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
     }
diff --git a/src/test/compile-fail/empty-struct-tuple-pat.rs b/src/test/compile-fail/empty-struct-tuple-pat.rs
new file mode 100644
index 00000000000..be90e3b26c7
--- /dev/null
+++ b/src/test/compile-fail/empty-struct-tuple-pat.rs
@@ -0,0 +1,47 @@
+// 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.
+
+// Can't use unit struct as enum pattern
+
+// aux-build:empty-struct.rs
+
+#![feature(relaxed_adts)]
+
+extern crate empty_struct;
+use empty_struct::*;
+
+struct Empty2();
+
+enum E {
+    Empty4()
+}
+
+// remove attribute after warning cycle and promoting warnings to errors
+fn main() {
+    let e2 = Empty2();
+    let e4 = E::Empty4();
+    let xe6 = XEmpty6();
+    let xe5 = XE::XEmpty5();
+
+    match e2 {
+        Empty2 => () //~ ERROR `Empty2` does not name a unit variant, unit struct or a constant
+    }
+    match xe6 {
+        XEmpty6 => () //~ ERROR `XEmpty6` does not name a unit variant, unit struct or a constant
+    }
+
+    match e4 {
+        E::Empty4 => () //~ ERROR `E::Empty4` does not name a unit variant, unit struct or a
+    }
+    match xe5 {
+        XE::XEmpty5 => (), //~ ERROR `XE::XEmpty5` does not name a unit variant, unit struct or a
+        _ => {},
+    }
+}
diff --git a/src/test/compile-fail/empty-struct-unit-pat.rs b/src/test/compile-fail/empty-struct-unit-pat-1.rs
similarity index 71%
rename from src/test/compile-fail/empty-struct-unit-pat.rs
rename to src/test/compile-fail/empty-struct-unit-pat-1.rs
index 05733762d37..aec4ad4cad4 100644
--- a/src/test/compile-fail/empty-struct-unit-pat.rs
+++ b/src/test/compile-fail/empty-struct-unit-pat-1.rs
@@ -12,6 +12,8 @@
 
 // aux-build:empty-struct.rs
 
+#![feature(relaxed_adts)]
+
 extern crate empty_struct;
 use empty_struct::*;
 
@@ -28,13 +30,6 @@ fn main() {
     let xe2 = XEmpty2;
     let xe4 = XE::XEmpty4;
 
-    // Rejected by parser as yet
-    // match e2 {
-    //     Empty2() => () // ERROR `Empty2` does not name a tuple variant or a tuple struct
-    // }
-    // match xe2 {
-    //     XEmpty2() => () // ERROR `XEmpty2` does not name a tuple variant or a tuple struct
-    // }
     match e2 {
         Empty2(..) => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct
             //~^ WARNING hard error
@@ -43,14 +38,7 @@ fn main() {
         XEmpty2(..) => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct
             //~^ WARNING hard error
     }
-    // Rejected by parser as yet
-    // match e4 {
-    //     E::Empty4() => () // ERROR `E::Empty4` does not name a tuple variant or a tuple struct
-    // }
-    // match xe4 {
-    //     XE::XEmpty4() => (), // ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
-    //     _ => {},
-    // }
+
     match e4 {
         E::Empty4(..) => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct
             //~^ WARNING hard error
diff --git a/src/test/compile-fail/empty-struct-unit-pat-2.rs b/src/test/compile-fail/empty-struct-unit-pat-2.rs
new file mode 100644
index 00000000000..6375a7f2338
--- /dev/null
+++ b/src/test/compile-fail/empty-struct-unit-pat-2.rs
@@ -0,0 +1,47 @@
+// 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.
+
+// Can't use unit struct as enum pattern
+
+// aux-build:empty-struct.rs
+
+#![feature(relaxed_adts)]
+
+extern crate empty_struct;
+use empty_struct::*;
+
+struct Empty2;
+
+enum E {
+    Empty4
+}
+
+// remove attribute after warning cycle and promoting warnings to errors
+fn main() {
+    let e2 = Empty2;
+    let e4 = E::Empty4;
+    let xe2 = XEmpty2;
+    let xe4 = XE::XEmpty4;
+
+    match e2 {
+        Empty2() => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct
+    }
+    match xe2 {
+        XEmpty2() => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct
+    }
+
+    match e4 {
+        E::Empty4() => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct
+    }
+    match xe4 {
+        XE::XEmpty4() => (), //~ ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
+        _ => {},
+    }
+}
diff --git a/src/test/compile-fail/feature-gate-relaxed-adts-2.rs b/src/test/compile-fail/feature-gate-relaxed-adts-2.rs
new file mode 100644
index 00000000000..a75f2647f49
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-relaxed-adts-2.rs
@@ -0,0 +1,27 @@
+// Copyright 2016 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.
+
+struct Z(u8, u8);
+
+enum E {
+    U(u8, u8),
+}
+
+fn main() {
+    match Z(0, 1) {
+        Z{..} => {} //~ ERROR tuple structs and variants in struct patterns are unstable
+    }
+    match E::U(0, 1) {
+        E::U{..} => {} //~ ERROR tuple structs and variants in struct patterns are unstable
+    }
+
+    let z1 = Z(0, 1);
+    let z2 = Z { ..z1 }; //~ ERROR tuple structs and variants in struct patterns are unstable
+}
diff --git a/src/test/run-pass/empty-struct-braces-gate-1.rs b/src/test/compile-fail/feature-gate-relaxed-adts.rs
similarity index 50%
rename from src/test/run-pass/empty-struct-braces-gate-1.rs
rename to src/test/compile-fail/feature-gate-relaxed-adts.rs
index 8287e151326..dc5e347aadf 100644
--- a/src/test/run-pass/empty-struct-braces-gate-1.rs
+++ b/src/test/compile-fail/feature-gate-relaxed-adts.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,16 +8,19 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Feature gate test for empty struct with braces
-// Can't define an empty braced struct
-
-struct Empty1 {}
-struct Empty2;
+struct S(); //~ ERROR empty tuple structs and enum variants are unstable
+struct Z(u8, u8);
 
 enum E {
-    Empty4 {},
-    Empty5,
+    V(), //~ ERROR empty tuple structs and enum variants are unstable
+    U(u8, u8),
 }
 
 fn main() {
+    match S() {
+        S() => {} //~ ERROR empty tuple structs patterns are unstable
+    }
+    match E::V() {
+        E::V() => {} //~ ERROR empty tuple structs patterns are unstable
+    }
 }
diff --git a/src/test/compile-fail/issue-12560-1.rs b/src/test/compile-fail/issue-12560-1.rs
deleted file mode 100644
index 80f551ebd1f..00000000000
--- a/src/test/compile-fail/issue-12560-1.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 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.
-
-// For style and consistency reasons, non-parametrized enum variants must
-// be used simply as `ident` instead of `ident ()`.
-// This test-case covers enum declaration.
-
-enum Foo {
-    Bar(), //~ ERROR empty tuple structs and enum variants are not allowed
-    //~^ HELP remove trailing `()` to make a unit struct or unit enum variant
-    Baz(), //~ ERROR empty tuple structs and enum variants are not allowed
-    //~^ HELP remove trailing `()` to make a unit struct or unit enum variant
-    Bazar
-}
-
-fn main() {
-    println!("{}", match Bar { Bar => 1, Baz => 2, Bazar => 3 }) //~ ERROR unresolved name `Bar`
-}
diff --git a/src/test/compile-fail/issue-12560-2.rs b/src/test/compile-fail/issue-12560-2.rs
deleted file mode 100644
index 9cbe2ebffe6..00000000000
--- a/src/test/compile-fail/issue-12560-2.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2014 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.
-
-// compile-flags: -Z continue-parse-after-error
-
-// For style and consistency reasons, non-parametrized enum variants must
-// be used simply as `ident` instead of `ident ()`.
-// This test-case covers enum matching.
-
-enum Foo {
-    Bar,
-    Baz,
-    Bazar
-}
-
-fn main() {
-    println!("{}", match Bar {
-        Bar() => 1, //~ ERROR nullary enum variants are written with no trailing `( )`
-        Baz() => 2, //~ ERROR nullary enum variants are written with no trailing `( )`
-        Bazar => 3
-    })
-}
diff --git a/src/test/compile-fail/issue-16819.rs b/src/test/compile-fail/issue-16819.rs
index b229b91c7cd..4301b47f2e9 100644
--- a/src/test/compile-fail/issue-16819.rs
+++ b/src/test/compile-fail/issue-16819.rs
@@ -8,13 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-struct TS ( //~ ERROR empty tuple structs and enum variants are not allowed
+struct TS ( //~ ERROR empty tuple structs and enum variants are unstable
     #[cfg(untrue)]
     i32,
 );
 
 enum E {
-    TV ( //~ ERROR empty tuple structs and enum variants are not allowed
+    TV ( //~ ERROR empty tuple structs and enum variants are unstable
         #[cfg(untrue)]
         i32,
     )
diff --git a/src/test/compile-fail/issue-17800.rs b/src/test/compile-fail/issue-17800.rs
index 5196b6ea877..58d580a5c1a 100644
--- a/src/test/compile-fail/issue-17800.rs
+++ b/src/test/compile-fail/issue-17800.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(relaxed_adts)]
+
 enum MyOption<T> {
     MySome(T),
     MyNone,
@@ -16,7 +18,8 @@ enum MyOption<T> {
 fn main() {
     match MyOption::MySome(42) {
         MyOption::MySome { x: 42 } => (),
-        //~^ ERROR `MyOption::MySome` does not name a struct or a struct variant
+        //~^ ERROR struct `MyOption::MySome` does not have a field named `x`
+        //~| ERROR pattern does not mention field `0`
         _ => (),
     }
 }
diff --git a/src/test/compile-fail/issue-27831.rs b/src/test/compile-fail/issue-27831.rs
deleted file mode 100644
index e20e6ea2319..00000000000
--- a/src/test/compile-fail/issue-27831.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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.
-
-struct Foo(u32);
-struct Bar;
-
-enum Enum {
-    Foo(u32),
-    Bar
-}
-
-fn main() {
-    let x = Foo(1);
-    Foo { ..x }; //~ ERROR `Foo` does not name a struct or a struct variant
-    let Foo { .. } = x; //~ ERROR `Foo` does not name a struct
-
-    let x = Bar;
-    Bar { ..x };
-    let Bar { .. } = x;
-
-    match Enum::Bar {
-        Enum::Bar { .. }
-           => {}
-        Enum::Foo { .. } //~ ERROR `Enum::Foo` does not name a struct
-           => {}
-    }
-}
diff --git a/src/test/compile-fail/issue-4736.rs b/src/test/compile-fail/issue-4736.rs
index 55983c672aa..a8a1b1482fc 100644
--- a/src/test/compile-fail/issue-4736.rs
+++ b/src/test/compile-fail/issue-4736.rs
@@ -8,8 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(relaxed_adts)]
+
 struct NonCopyable(());
 
 fn main() {
-    let z = NonCopyable{ p: () }; //~ ERROR `NonCopyable` does not name a struct or a struct variant
+    let z = NonCopyable{ p: () }; //~ ERROR structure `NonCopyable` has no field named `p`
 }
diff --git a/src/test/compile-fail/struct-no-fields-enumlike.rs b/src/test/compile-fail/struct-no-fields-enumlike.rs
deleted file mode 100644
index 6bdbae1e4b9..00000000000
--- a/src/test/compile-fail/struct-no-fields-enumlike.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2014 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.
-
-struct Foo(); //~ ERROR empty tuple structs and enum variants are not allowed
-
-fn main() {}
diff --git a/src/test/run-pass/auxiliary/empty-struct.rs b/src/test/run-pass/auxiliary/empty-struct.rs
index 22f65c2b0d8..b599d7bee73 100644
--- a/src/test/run-pass/auxiliary/empty-struct.rs
+++ b/src/test/run-pass/auxiliary/empty-struct.rs
@@ -8,10 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(relaxed_adts)]
+
 pub struct XEmpty1 {}
 pub struct XEmpty2;
+pub struct XEmpty7();
 
 pub enum XE {
     XEmpty3 {},
     XEmpty4,
+    XEmpty6(),
 }
diff --git a/src/test/run-pass/empty-struct-braces-gate-2.rs b/src/test/run-pass/empty-struct-braces-gate-2.rs
deleted file mode 100644
index 0ec3c89859e..00000000000
--- a/src/test/run-pass/empty-struct-braces-gate-2.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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 gate test for empty struct with braces
-// Can't use braced expressions and patterns with structs defined without braces
-
-struct Empty2;
-
-enum E {
-    Empty5,
-}
-
-fn main() {
-    let e2: Empty2 = Empty2 {};
-    let e2: Empty2 = Empty2;
-    let e5: E = E::Empty5 {};
-    let e5: E = E::Empty5;
-
-    match e2 {
-        Empty2 {} => {}
-    }
-    match e2 {
-        Empty2 => {}
-    }
-    match e2 {
-        Empty2 { .. } => {}
-    }
-    match e5 {
-        E::Empty5 {} => {}
-    }
-    match e5 {
-        E::Empty5 => {}
-    }
-    match e5 {
-        E::Empty5 { .. } => {}
-    }
-
-    let e22 = Empty2 { ..e2 };
-}
diff --git a/src/test/run-pass/empty-struct-braces.rs b/src/test/run-pass/empty-struct-braces.rs
index 0060150fbec..48966f24a2e 100644
--- a/src/test/run-pass/empty-struct-braces.rs
+++ b/src/test/run-pass/empty-struct-braces.rs
@@ -13,11 +13,14 @@
 
 // aux-build:empty-struct.rs
 
+#![feature(relaxed_adts)]
+
 extern crate empty_struct;
 use empty_struct::*;
 
 struct Empty1 {}
 struct Empty2;
+struct Empty7();
 
 #[derive(PartialEq, Eq)]
 struct Empty3 {}
@@ -27,6 +30,7 @@ const Empty3: Empty3 = Empty3 {};
 enum E {
     Empty4 {},
     Empty5,
+    Empty6(),
 }
 
 fn local() {
@@ -38,6 +42,12 @@ fn local() {
     let e4: E = E::Empty4 {};
     let e5: E = E::Empty5 {};
     let e5: E = E::Empty5;
+    let e6: E = E::Empty6 {};
+    let e6: E = E::Empty6();
+    let ctor6: fn() -> E = E::Empty6;
+    let e7: Empty7 = Empty7 {};
+    let e7: Empty7 = Empty7();
+    let ctor7: fn() -> Empty7 = Empty7;
 
     match e1 {
         Empty1 {} => {}
@@ -56,6 +66,13 @@ fn local() {
         E::Empty5 {} => {}
         _ => {}
     }
+    match e6 {
+        E::Empty6 {} => {}
+        _ => {}
+    }
+    match e7 {
+        Empty7 {} => {}
+    }
 
     match e1 {
         Empty1 { .. } => {}
@@ -74,6 +91,13 @@ fn local() {
         E::Empty5 { .. } => {}
         _ => {}
     }
+    match e6 {
+        E::Empty6 { .. } => {}
+        _ => {}
+    }
+    match e7 {
+        Empty7 { .. } => {}
+    }
 
     match e2 {
         Empty2 => {}
@@ -85,10 +109,25 @@ fn local() {
         E::Empty5 => {}
         _ => {}
     }
+    match e6 {
+        E::Empty6() => {}
+        _ => {}
+    }
+    match e6 {
+        E::Empty6(..) => {}
+        _ => {}
+    }
+    match e7 {
+        Empty7() => {}
+    }
+    match e7 {
+        Empty7(..) => {}
+    }
 
     let e11: Empty1 = Empty1 { ..e1 };
     let e22: Empty2 = Empty2 { ..e2 };
     let e33: Empty3 = Empty3 { ..e3 };
+    let e77: Empty7 = Empty7 { ..e7 };
 }
 
 fn xcrate() {
@@ -98,6 +137,12 @@ fn xcrate() {
     let e3: XE = XE::XEmpty3 {};
     let e4: XE = XE::XEmpty4 {};
     let e4: XE = XE::XEmpty4;
+    let e6: XE = XE::XEmpty6 {};
+    let e6: XE = XE::XEmpty6();
+    let ctor6: fn() -> XE = XE::XEmpty6;
+    let e7: XEmpty7 = XEmpty7 {};
+    let e7: XEmpty7 = XEmpty7();
+    let ctor7: fn() -> XEmpty7 = XEmpty7;
 
     match e1 {
         XEmpty1 {} => {}
@@ -113,6 +158,13 @@ fn xcrate() {
         XE::XEmpty4 {} => {}
         _ => {}
     }
+    match e6 {
+        XE::XEmpty6 {} => {}
+        _ => {}
+    }
+    match e7 {
+        XEmpty7 {} => {}
+    }
 
     match e1 {
         XEmpty1 { .. } => {}
@@ -128,6 +180,13 @@ fn xcrate() {
         XE::XEmpty4 { .. } => {}
         _ => {}
     }
+    match e6 {
+        XE::XEmpty6 { .. } => {}
+        _ => {}
+    }
+    match e7 {
+        XEmpty7 { .. } => {}
+    }
 
     match e2 {
         XEmpty2 => {}
@@ -136,9 +195,24 @@ fn xcrate() {
         XE::XEmpty4 => {}
         _ => {}
     }
+    match e6 {
+        XE::XEmpty6() => {}
+        _ => {}
+    }
+    match e6 {
+        XE::XEmpty6(..) => {}
+        _ => {}
+    }
+    match e7 {
+        XEmpty7() => {}
+    }
+    match e7 {
+        XEmpty7(..) => {}
+    }
 
     let e11: XEmpty1 = XEmpty1 { ..e1 };
     let e22: XEmpty2 = XEmpty2 { ..e2 };
+    let e77: XEmpty7 = XEmpty7 { ..e7 };
 }
 
 fn main() {

From f6624782d41dce401a4103240daa06011ed326a5 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Fri, 29 Jul 2016 23:47:55 +0300
Subject: [PATCH 2/2] Parse numeric fields in struct expressions and patterns

---
 src/libsyntax/parse/parser.rs           | 13 +++++++++++--
 src/test/compile-fail/numeric-fields.rs | 20 ++++++++++++++++++++
 src/test/run-pass/numeric-fields.rs     | 23 +++++++++++++++++++++++
 3 files changed, 54 insertions(+), 2 deletions(-)
 create mode 100644 src/test/compile-fail/numeric-fields.rs
 create mode 100644 src/test/run-pass/numeric-fields.rs

diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 1b32632a06f..4c279b2fe48 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2009,10 +2009,19 @@ impl<'a> Parser<'a> {
         }
     }
 
+    pub fn parse_field_name(&mut self) -> PResult<'a, Ident> {
+        if let token::Literal(token::Integer(name), None) = self.token {
+            self.bump();
+            Ok(Ident::with_empty_ctxt(name))
+        } else {
+            self.parse_ident()
+        }
+    }
+
     /// Parse ident COLON expr
     pub fn parse_field(&mut self) -> PResult<'a, Field> {
         let lo = self.span.lo;
-        let i = self.parse_ident()?;
+        let i = self.parse_field_name()?;
         let hi = self.last_span.hi;
         self.expect(&token::Colon)?;
         let e = self.parse_expr()?;
@@ -3508,7 +3517,7 @@ impl<'a> Parser<'a> {
             // Check if a colon exists one ahead. This means we're parsing a fieldname.
             let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
                 // Parsing a pattern of the form "fieldname: pat"
-                let fieldname = self.parse_ident()?;
+                let fieldname = self.parse_field_name()?;
                 self.bump();
                 let pat = self.parse_pat()?;
                 hi = pat.span.hi;
diff --git a/src/test/compile-fail/numeric-fields.rs b/src/test/compile-fail/numeric-fields.rs
new file mode 100644
index 00000000000..480d2dcdddd
--- /dev/null
+++ b/src/test/compile-fail/numeric-fields.rs
@@ -0,0 +1,20 @@
+// Copyright 2016 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(relaxed_adts)]
+
+struct S(u8, u16);
+
+fn main() {
+    let s = S{0b1: 10, 0: 11}; //~ ERROR structure `S` has no field named `0b1`
+    match s {
+        S{0: a, 0x1: b, ..} => {} //~ ERROR does not have a field named `0x1`
+    }
+}
diff --git a/src/test/run-pass/numeric-fields.rs b/src/test/run-pass/numeric-fields.rs
new file mode 100644
index 00000000000..25e5a2a0fd5
--- /dev/null
+++ b/src/test/run-pass/numeric-fields.rs
@@ -0,0 +1,23 @@
+// Copyright 2016 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(relaxed_adts)]
+
+struct S(u8, u16);
+
+fn main() {
+    let s = S{1: 10, 0: 11};
+    match s {
+        S{0: a, 1: b, ..} => {
+            assert_eq!(a, 11);
+            assert_eq!(b, 10);
+        }
+    }
+}