Skip to content

Commit d3c3de8

Browse files
authored
Auto merge of #35138 - petrochenkov:clarify, r=eddyb
Implement RFC 1506 "Clarify the relationships between various kinds of structs and variants" cc #35626
2 parents 1deb02e + f662478 commit d3c3de8

24 files changed

+330
-218
lines changed

src/librustc_passes/ast_validation.rs

-21
Original file line numberDiff line numberDiff line change
@@ -197,27 +197,6 @@ impl<'a> Visitor for AstValidator<'a> {
197197
visit::walk_foreign_item(self, fi)
198198
}
199199

200-
fn visit_variant_data(&mut self,
201-
vdata: &VariantData,
202-
_: Ident,
203-
_: &Generics,
204-
_: NodeId,
205-
span: Span) {
206-
if vdata.fields().is_empty() {
207-
if vdata.is_tuple() {
208-
self.err_handler()
209-
.struct_span_err(span,
210-
"empty tuple structs and enum variants are not allowed, use \
211-
unit structs and enum variants instead")
212-
.span_help(span,
213-
"remove trailing `()` to make a unit struct or unit enum variant")
214-
.emit();
215-
}
216-
}
217-
218-
visit::walk_struct_def(self, vdata)
219-
}
220-
221200
fn visit_vis(&mut self, vis: &Visibility) {
222201
match *vis {
223202
Visibility::Restricted { ref path, .. } => {

src/librustc_typeck/check/mod.rs

+19-8
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ use syntax::ast;
116116
use syntax::attr;
117117
use syntax::attr::AttrMetaMethods;
118118
use syntax::codemap::{self, Spanned};
119+
use syntax::feature_gate::{GateIssue, emit_feature_err};
119120
use syntax::parse::token::{self, InternedString, keywords};
120121
use syntax::ptr::P;
121122
use syntax::util::lev_distance::find_best_match_for_name;
@@ -1700,7 +1701,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
17001701
node_id: ast::NodeId)
17011702
-> Ty<'tcx> {
17021703
debug!("instantiate_type_path(did={:?}, path={:?})", did, path);
1703-
let type_scheme = self.tcx.lookup_item_type(did);
1704+
let mut type_scheme = self.tcx.lookup_item_type(did);
1705+
if type_scheme.ty.is_fn() {
1706+
// Tuple variants have fn type even in type namespace, extract true variant type from it
1707+
let fn_ret = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap().unwrap();
1708+
type_scheme = ty::TypeScheme { ty: fn_ret, generics: type_scheme.generics }
1709+
}
17041710
let type_predicates = self.tcx.lookup_predicates(did);
17051711
let substs = AstConv::ast_path_substs_for_ty(self, self,
17061712
path.span,
@@ -3244,19 +3250,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
32443250
}
32453251
_ => None
32463252
};
3247-
if variant.is_none() || variant.unwrap().kind == ty::VariantKind::Tuple {
3248-
// Reject tuple structs for now, braced and unit structs are allowed.
3253+
3254+
if let Some(variant) = variant {
3255+
if variant.kind == ty::VariantKind::Tuple &&
3256+
!self.tcx.sess.features.borrow().relaxed_adts {
3257+
emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic,
3258+
"relaxed_adts", span, GateIssue::Language,
3259+
"tuple structs and variants in struct patterns are unstable");
3260+
}
3261+
let ty = self.instantiate_type_path(def.def_id(), path, node_id);
3262+
Some((variant, ty))
3263+
} else {
32493264
struct_span_err!(self.tcx.sess, path.span, E0071,
32503265
"`{}` does not name a struct or a struct variant",
32513266
pprust::path_to_string(path))
32523267
.span_label(path.span, &format!("not a struct"))
32533268
.emit();
3254-
3255-
return None;
3269+
None
32563270
}
3257-
3258-
let ty = self.instantiate_type_path(def.def_id(), path, node_id);
3259-
Some((variant.unwrap(), ty))
32603271
}
32613272

32623273
fn check_expr_struct(&self,

src/libsyntax/feature_gate.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,11 @@ declare_features! (
280280
(active, dotdot_in_tuple_patterns, "1.10.0", Some(33627)),
281281

282282
// Allows `impl Trait` in function return types.
283-
(active, conservative_impl_trait, "1.12.0", Some(34511))
283+
(active, conservative_impl_trait, "1.12.0", Some(34511)),
284+
285+
// Allows tuple structs and variants in more contexts,
286+
// Permits numeric fields in struct expressions and patterns.
287+
(active, relaxed_adts, "1.12.0", Some(35626))
284288
);
285289

286290
declare_features! (
@@ -1022,9 +1026,8 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
10221026
}
10231027
PatKind::TupleStruct(_, ref fields, ddpos)
10241028
if ddpos.is_none() && fields.is_empty() => {
1025-
self.context.span_handler.struct_span_err(pattern.span,
1026-
"nullary enum variants are written with \
1027-
no trailing `( )`").emit();
1029+
gate_feature_post!(&self, relaxed_adts, pattern.span,
1030+
"empty tuple structs patterns are unstable");
10281031
}
10291032
_ => {}
10301033
}
@@ -1107,6 +1110,19 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
11071110
visit::walk_impl_item(self, ii);
11081111
}
11091112

1113+
fn visit_variant_data(&mut self, vdata: &ast::VariantData, _: ast::Ident,
1114+
_: &ast::Generics, _: NodeId, span: Span) {
1115+
if vdata.fields().is_empty() {
1116+
if vdata.is_tuple() {
1117+
gate_feature_post!(&self, relaxed_adts, span,
1118+
"empty tuple structs and enum variants are unstable, \
1119+
use unit structs and enum variants instead");
1120+
}
1121+
}
1122+
1123+
visit::walk_struct_def(self, vdata)
1124+
}
1125+
11101126
fn visit_vis(&mut self, vis: &ast::Visibility) {
11111127
let span = match *vis {
11121128
ast::Visibility::Crate(span) => span,

src/libsyntax/parse/parser.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -2009,10 +2009,19 @@ impl<'a> Parser<'a> {
20092009
}
20102010
}
20112011

2012+
pub fn parse_field_name(&mut self) -> PResult<'a, Ident> {
2013+
if let token::Literal(token::Integer(name), None) = self.token {
2014+
self.bump();
2015+
Ok(Ident::with_empty_ctxt(name))
2016+
} else {
2017+
self.parse_ident()
2018+
}
2019+
}
2020+
20122021
/// Parse ident COLON expr
20132022
pub fn parse_field(&mut self) -> PResult<'a, Field> {
20142023
let lo = self.span.lo;
2015-
let i = self.parse_ident()?;
2024+
let i = self.parse_field_name()?;
20162025
let hi = self.last_span.hi;
20172026
self.expect(&token::Colon)?;
20182027
let e = self.parse_expr()?;
@@ -3508,7 +3517,7 @@ impl<'a> Parser<'a> {
35083517
// Check if a colon exists one ahead. This means we're parsing a fieldname.
35093518
let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
35103519
// Parsing a pattern of the form "fieldname: pat"
3511-
let fieldname = self.parse_ident()?;
3520+
let fieldname = self.parse_field_name()?;
35123521
self.bump();
35133522
let pat = self.parse_pat()?;
35143523
hi = pat.span.hi;

src/test/compile-fail/E0071.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
enum Foo { FirstValue(i32) }
11+
enum Foo {}
1212

1313
fn main() {
14-
let u = Foo::FirstValue { value: 0 };
15-
//~^ ERROR `Foo::FirstValue` does not name a struct or a struct variant [E0071]
14+
let u = Foo { value: 0 };
15+
//~^ ERROR `Foo` does not name a struct or a struct variant [E0071]
1616
//~| NOTE not a struct
1717

1818
let t = u32 { value: 4 };

src/test/compile-fail/auxiliary/empty-struct.rs

+4
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![feature(relaxed_adts)]
12+
1113
pub struct XEmpty1 {}
1214
pub struct XEmpty2;
15+
pub struct XEmpty6();
1316

1417
pub enum XE {
1518
XEmpty3 {},
1619
XEmpty4,
20+
XEmpty5(),
1721
}

src/test/compile-fail/empty-struct-braces-pat-2.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
// aux-build:empty-struct.rs
1414

15+
#![feature(relaxed_adts)]
16+
1517
extern crate empty_struct;
1618
use empty_struct::*;
1719

@@ -21,13 +23,12 @@ fn main() {
2123
let e1 = Empty1 {};
2224
let xe1 = XEmpty1 {};
2325

24-
// Rejected by parser as yet
25-
// match e1 {
26-
// Empty1() => () // ERROR unresolved enum variant, struct or const `Empty1`
27-
// }
28-
// match xe1 {
29-
// XEmpty1() => () // ERROR unresolved enum variant, struct or const `XEmpty1`
30-
// }
26+
match e1 {
27+
Empty1() => () //~ ERROR unresolved variant or struct `Empty1`
28+
}
29+
match xe1 {
30+
XEmpty1() => () //~ ERROR unresolved variant or struct `XEmpty1`
31+
}
3132
match e1 {
3233
Empty1(..) => () //~ ERROR unresolved variant or struct `Empty1`
3334
}

src/test/compile-fail/empty-struct-braces-pat-3.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
// aux-build:empty-struct.rs
1414

15+
#![feature(relaxed_adts)]
16+
1517
extern crate empty_struct;
1618
use empty_struct::*;
1719

@@ -23,13 +25,12 @@ fn main() {
2325
let e3 = E::Empty3 {};
2426
let xe3 = XE::XEmpty3 {};
2527

26-
// Rejected by parser as yet
27-
// match e3 {
28-
// E::Empty3() => () // ERROR `E::Empty3` does not name a tuple variant or a tuple struct
29-
// }
30-
// match xe3 {
31-
// E::Empty3() => () // ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct
32-
// }
28+
match e3 {
29+
E::Empty3() => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
30+
}
31+
match xe3 {
32+
XE::XEmpty3() => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct
33+
}
3334
match e3 {
3435
E::Empty3(..) => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
3536
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Can't use unit struct as enum pattern
12+
13+
// aux-build:empty-struct.rs
14+
15+
#![feature(relaxed_adts)]
16+
17+
extern crate empty_struct;
18+
use empty_struct::*;
19+
20+
struct Empty2();
21+
22+
enum E {
23+
Empty4()
24+
}
25+
26+
// remove attribute after warning cycle and promoting warnings to errors
27+
fn main() {
28+
let e2 = Empty2();
29+
let e4 = E::Empty4();
30+
let xe6 = XEmpty6();
31+
let xe5 = XE::XEmpty5();
32+
33+
match e2 {
34+
Empty2 => () //~ ERROR `Empty2` does not name a unit variant, unit struct or a constant
35+
}
36+
match xe6 {
37+
XEmpty6 => () //~ ERROR `XEmpty6` does not name a unit variant, unit struct or a constant
38+
}
39+
40+
match e4 {
41+
E::Empty4 => () //~ ERROR `E::Empty4` does not name a unit variant, unit struct or a
42+
}
43+
match xe5 {
44+
XE::XEmpty5 => (), //~ ERROR `XE::XEmpty5` does not name a unit variant, unit struct or a
45+
_ => {},
46+
}
47+
}

src/test/compile-fail/empty-struct-unit-pat.rs src/test/compile-fail/empty-struct-unit-pat-1.rs

+3-15
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
// aux-build:empty-struct.rs
1414

15+
#![feature(relaxed_adts)]
16+
1517
extern crate empty_struct;
1618
use empty_struct::*;
1719

@@ -28,13 +30,6 @@ fn main() {
2830
let xe2 = XEmpty2;
2931
let xe4 = XE::XEmpty4;
3032

31-
// Rejected by parser as yet
32-
// match e2 {
33-
// Empty2() => () // ERROR `Empty2` does not name a tuple variant or a tuple struct
34-
// }
35-
// match xe2 {
36-
// XEmpty2() => () // ERROR `XEmpty2` does not name a tuple variant or a tuple struct
37-
// }
3833
match e2 {
3934
Empty2(..) => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct
4035
//~^ WARNING hard error
@@ -43,14 +38,7 @@ fn main() {
4338
XEmpty2(..) => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct
4439
//~^ WARNING hard error
4540
}
46-
// Rejected by parser as yet
47-
// match e4 {
48-
// E::Empty4() => () // ERROR `E::Empty4` does not name a tuple variant or a tuple struct
49-
// }
50-
// match xe4 {
51-
// XE::XEmpty4() => (), // ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
52-
// _ => {},
53-
// }
41+
5442
match e4 {
5543
E::Empty4(..) => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct
5644
//~^ WARNING hard error
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Can't use unit struct as enum pattern
12+
13+
// aux-build:empty-struct.rs
14+
15+
#![feature(relaxed_adts)]
16+
17+
extern crate empty_struct;
18+
use empty_struct::*;
19+
20+
struct Empty2;
21+
22+
enum E {
23+
Empty4
24+
}
25+
26+
// remove attribute after warning cycle and promoting warnings to errors
27+
fn main() {
28+
let e2 = Empty2;
29+
let e4 = E::Empty4;
30+
let xe2 = XEmpty2;
31+
let xe4 = XE::XEmpty4;
32+
33+
match e2 {
34+
Empty2() => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct
35+
}
36+
match xe2 {
37+
XEmpty2() => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct
38+
}
39+
40+
match e4 {
41+
E::Empty4() => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct
42+
}
43+
match xe4 {
44+
XE::XEmpty4() => (), //~ ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
45+
_ => {},
46+
}
47+
}

0 commit comments

Comments
 (0)