From 59be332a1b3b190ec5dfdb6768e80f9d312a0c6b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov 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 341c9d820e651..1e8da29ee7400 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 c2c93161ce703..0c8e6d990a644 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 f550e7d2a0515..ad52184a6dcb0 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 6f0e55efffc92..c13ba7bf13671 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 22f65c2b0d8f8..dcbb0ce178bd8 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 0522a654a8528..52481517ce751 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 88249fc422f2c..cb859fe7501c6 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 0000000000000..be90e3b26c7ef --- /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 or the MIT license +// , 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 05733762d37ad..aec4ad4cad401 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 0000000000000..6375a7f23381e --- /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 or the MIT license +// , 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 0000000000000..a75f2647f49a4 --- /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 or the MIT license +// , 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 8287e151326d8..dc5e347aadf30 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 80f551ebd1f7c..0000000000000 --- 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 or the MIT license -// , 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 9cbe2ebffe694..0000000000000 --- 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 or the MIT license -// , 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 b229b91c7cd14..4301b47f2e9b2 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 5196b6ea877f8..58d580a5c1a1c 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 { MySome(T), MyNone, @@ -16,7 +18,8 @@ enum MyOption { 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 e20e6ea23198c..0000000000000 --- 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 or the MIT license -// , 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 55983c672aa08..a8a1b1482fc08 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 6bdbae1e4b9d9..0000000000000 --- 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 or the MIT license -// , 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 22f65c2b0d8f8..b599d7bee73de 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 0ec3c89859e62..0000000000000 --- 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 or the MIT license -// , 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 0060150fbece0..48966f24a2e5e 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 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 1b32632a06f4e..4c279b2fe4832 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 0000000000000..480d2dcddddd4 --- /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 or the MIT license +// , 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 0000000000000..25e5a2a0fd5ba --- /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 or the MIT license +// , 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); + } + } +}