@@ -4875,9 +4875,6 @@ impl<'a> Parser<'a> {
48754875 self . span_err ( ty. span , "`virtual` structs have been removed from the language" ) ;
48764876 }
48774877
4878- let mut fields: Vec < StructField > ;
4879- let is_tuple_like;
4880-
48814878 // There is a special case worth noting here, as reported in issue #17904.
48824879 // If we are parsing a tuple struct it is the case that the where clause
48834880 // should follow the field list. Like so:
@@ -4892,68 +4889,102 @@ impl<'a> Parser<'a> {
48924889 // Otherwise if we look ahead and see a paren we parse a tuple-style
48934890 // struct.
48944891
4895- // Will parse the where-clause if it precedes the brace.
4896- self . parse_where_clause ( & mut generics) ;
4892+ let ( fields, ctor_id) = if self . token . is_keyword ( keywords:: Where ) {
4893+ self . parse_where_clause ( & mut generics) ;
4894+ if self . eat ( & token:: Semi ) {
4895+ // If we see a: `struct Foo<T> where T: Copy;` style decl.
4896+ ( Vec :: new ( ) , Some ( ast:: DUMMY_NODE_ID ) )
4897+ } else {
4898+ // If we see: `struct Foo<T> where T: Copy { ... }`
4899+ ( self . parse_record_struct_body ( & class_name) , None )
4900+ }
4901+ // No `where` so: `struct Foo<T>;`
4902+ } else if self . eat ( & token:: Semi ) {
4903+ ( Vec :: new ( ) , Some ( ast:: DUMMY_NODE_ID ) )
4904+ // Record-style struct definition
4905+ } else if self . token == token:: OpenDelim ( token:: Brace ) {
4906+ let fields = self . parse_record_struct_body ( & class_name) ;
4907+ ( fields, None )
4908+ // Tuple-style struct definition with optional where-clause.
4909+ } else {
4910+ let fields = self . parse_tuple_struct_body ( & class_name, & mut generics) ;
4911+ ( fields, Some ( ast:: DUMMY_NODE_ID ) )
4912+ } ;
48974913
4914+ ( class_name,
4915+ ItemStruct ( P ( ast:: StructDef {
4916+ fields : fields,
4917+ ctor_id : ctor_id,
4918+ } ) , generics) ,
4919+ None )
4920+ }
4921+
4922+ pub fn parse_record_struct_body ( & mut self , class_name : & ast:: Ident ) -> Vec < StructField > {
4923+ let mut fields = Vec :: new ( ) ;
48984924 if self . eat ( & token:: OpenDelim ( token:: Brace ) ) {
4899- // It's a record-like struct.
4900- is_tuple_like = false ;
4901- fields = Vec :: new ( ) ;
49024925 while self . token != token:: CloseDelim ( token:: Brace ) {
49034926 fields. push ( self . parse_struct_decl_field ( true ) ) ;
49044927 }
4928+
49054929 if fields. len ( ) == 0 {
49064930 self . fatal ( format ! ( "unit-like struct definition should be \
4907- written as `struct {};`",
4908- token:: get_ident( class_name) ) [ ] ) ;
4931+ written as `struct {};`",
4932+ token:: get_ident( class_name. clone ( ) ) ) [ ] ) ;
49094933 }
4934+
49104935 self . bump ( ) ;
4911- } else if self . check ( & token:: OpenDelim ( token:: Paren ) ) {
4912- // It's a tuple-like struct.
4913- is_tuple_like = true ;
4914- fields = self . parse_unspanned_seq (
4936+ } else {
4937+ let token_str = self . this_token_to_string ( ) ;
4938+ self . fatal ( format ! ( "expected `where`, or `{}` after struct \
4939+ name, found `{}`", "{" ,
4940+ token_str) [ ] ) ;
4941+ }
4942+
4943+ fields
4944+ }
4945+
4946+ pub fn parse_tuple_struct_body ( & mut self ,
4947+ class_name : & ast:: Ident ,
4948+ generics : & mut ast:: Generics )
4949+ -> Vec < StructField > {
4950+ // This is the case where we find `struct Foo<T>(T) where T: Copy;`
4951+ if self . check ( & token:: OpenDelim ( token:: Paren ) ) {
4952+ let fields = self . parse_unspanned_seq (
49154953 & token:: OpenDelim ( token:: Paren ) ,
49164954 & token:: CloseDelim ( token:: Paren ) ,
49174955 seq_sep_trailing_allowed ( token:: Comma ) ,
49184956 |p| {
4919- let attrs = p. parse_outer_attributes ( ) ;
4920- let lo = p. span . lo ;
4921- let struct_field_ = ast:: StructField_ {
4922- kind : UnnamedField ( p. parse_visibility ( ) ) ,
4923- id : ast:: DUMMY_NODE_ID ,
4924- ty : p. parse_ty_sum ( ) ,
4925- attrs : attrs,
4926- } ;
4927- spanned ( lo, p. span . hi , struct_field_)
4928- } ) ;
4957+ let attrs = p. parse_outer_attributes ( ) ;
4958+ let lo = p. span . lo ;
4959+ let struct_field_ = ast:: StructField_ {
4960+ kind : UnnamedField ( p. parse_visibility ( ) ) ,
4961+ id : ast:: DUMMY_NODE_ID ,
4962+ ty : p. parse_ty_sum ( ) ,
4963+ attrs : attrs,
4964+ } ;
4965+ spanned ( lo, p. span . hi , struct_field_)
4966+ } ) ;
4967+
49294968 if fields. len ( ) == 0 {
49304969 self . fatal ( format ! ( "unit-like struct definition should be \
4931- written as `struct {};`",
4932- token:: get_ident( class_name) ) [ ] ) ;
4970+ written as `struct {};`",
4971+ token:: get_ident( class_name. clone ( ) ) ) [ ] ) ;
49334972 }
4934- self . parse_where_clause ( & mut generics) ;
4973+
4974+ self . parse_where_clause ( generics) ;
49354975 self . expect ( & token:: Semi ) ;
4936- } else if self . token . is_keyword ( keywords:: Where ) || self . eat ( & token:: Semi ) {
4937- // We can find a where clause here.
4938- self . parse_where_clause ( & mut generics) ;
4939- // It's a unit-like struct.
4940- is_tuple_like = true ;
4941- fields = Vec :: new ( ) ;
4976+ fields
4977+ // This is the case where we just see struct Foo<T> where T: Copy;
4978+ } else if self . token . is_keyword ( keywords:: Where ) {
4979+ self . parse_where_clause ( generics) ;
4980+ self . expect ( & token:: Semi ) ;
4981+ Vec :: new ( )
4982+ // This case is where we see: `struct Foo<T>;`
49424983 } else {
49434984 let token_str = self . this_token_to_string ( ) ;
4944- self . fatal ( format ! ( "expected `{}`, `(`, or `;` after struct \
4945- name, found `{}`", "{" ,
4946- token_str) [ ] )
4985+ self . fatal ( format ! ( "expected `where`, `{}`, `(`, or `;` after struct \
4986+ name, found `{}`", "{" , token_str) [ ] ) ;
49474987 }
4948-
4949- let _ = ast:: DUMMY_NODE_ID ; // FIXME: Workaround for crazy bug.
4950- let new_id = ast:: DUMMY_NODE_ID ;
4951- ( class_name,
4952- ItemStruct ( P ( ast:: StructDef {
4953- fields : fields,
4954- ctor_id : if is_tuple_like { Some ( new_id) } else { None } ,
4955- } ) , generics) ,
4956- None )
49574988 }
49584989
49594990 /// Parse a structure field declaration
0 commit comments