@@ -4885,67 +4885,116 @@ impl<'a> Parser<'a> {
4885
4885
self . span_err ( ty. span , "`virtual` structs have been removed from the language" ) ;
4886
4886
}
4887
4887
4888
- self . parse_where_clause ( & mut generics) ;
4888
+ // There is a special case worth noting here, as reported in issue #17904.
4889
+ // If we are parsing a tuple struct it is the case that the where clause
4890
+ // should follow the field list. Like so:
4891
+ //
4892
+ // struct Foo<T>(T) where T: Copy;
4893
+ //
4894
+ // If we are parsing a normal record-style struct it is the case
4895
+ // that the where clause comes before the body, and after the generics.
4896
+ // So if we look ahead and see a brace or a where-clause we begin
4897
+ // parsing a record style struct.
4898
+ //
4899
+ // Otherwise if we look ahead and see a paren we parse a tuple-style
4900
+ // struct.
4901
+
4902
+ let ( fields, ctor_id) = if self . token . is_keyword ( keywords:: Where ) {
4903
+ self . parse_where_clause ( & mut generics) ;
4904
+ if self . eat ( & token:: Semi ) {
4905
+ // If we see a: `struct Foo<T> where T: Copy;` style decl.
4906
+ ( Vec :: new ( ) , Some ( ast:: DUMMY_NODE_ID ) )
4907
+ } else {
4908
+ // If we see: `struct Foo<T> where T: Copy { ... }`
4909
+ ( self . parse_record_struct_body ( & class_name) , None )
4910
+ }
4911
+ // No `where` so: `struct Foo<T>;`
4912
+ } else if self . eat ( & token:: Semi ) {
4913
+ ( Vec :: new ( ) , Some ( ast:: DUMMY_NODE_ID ) )
4914
+ // Record-style struct definition
4915
+ } else if self . token == token:: OpenDelim ( token:: Brace ) {
4916
+ let fields = self . parse_record_struct_body ( & class_name) ;
4917
+ ( fields, None )
4918
+ // Tuple-style struct definition with optional where-clause.
4919
+ } else {
4920
+ let fields = self . parse_tuple_struct_body ( & class_name, & mut generics) ;
4921
+ ( fields, Some ( ast:: DUMMY_NODE_ID ) )
4922
+ } ;
4889
4923
4890
- let mut fields: Vec < StructField > ;
4891
- let is_tuple_like;
4924
+ ( class_name,
4925
+ ItemStruct ( P ( ast:: StructDef {
4926
+ fields : fields,
4927
+ ctor_id : ctor_id,
4928
+ } ) , generics) ,
4929
+ None )
4930
+ }
4892
4931
4932
+ pub fn parse_record_struct_body ( & mut self , class_name : & ast:: Ident ) -> Vec < StructField > {
4933
+ let mut fields = Vec :: new ( ) ;
4893
4934
if self . eat ( & token:: OpenDelim ( token:: Brace ) ) {
4894
- // It's a record-like struct.
4895
- is_tuple_like = false ;
4896
- fields = Vec :: new ( ) ;
4897
4935
while self . token != token:: CloseDelim ( token:: Brace ) {
4898
4936
fields. push ( self . parse_struct_decl_field ( true ) ) ;
4899
4937
}
4938
+
4900
4939
if fields. len ( ) == 0 {
4901
4940
self . fatal ( format ! ( "unit-like struct definition should be \
4902
- written as `struct {};`",
4903
- token:: get_ident( class_name) ) [ ] ) ;
4941
+ written as `struct {};`",
4942
+ token:: get_ident( class_name. clone ( ) ) ) [ ] ) ;
4904
4943
}
4944
+
4905
4945
self . bump ( ) ;
4906
- } else if self . check ( & token:: OpenDelim ( token:: Paren ) ) {
4907
- // It's a tuple-like struct.
4908
- is_tuple_like = true ;
4909
- fields = self . parse_unspanned_seq (
4946
+ } else {
4947
+ let token_str = self . this_token_to_string ( ) ;
4948
+ self . fatal ( format ! ( "expected `where`, or `{}` after struct \
4949
+ name, found `{}`", "{" ,
4950
+ token_str) [ ] ) ;
4951
+ }
4952
+
4953
+ fields
4954
+ }
4955
+
4956
+ pub fn parse_tuple_struct_body ( & mut self ,
4957
+ class_name : & ast:: Ident ,
4958
+ generics : & mut ast:: Generics )
4959
+ -> Vec < StructField > {
4960
+ // This is the case where we find `struct Foo<T>(T) where T: Copy;`
4961
+ if self . check ( & token:: OpenDelim ( token:: Paren ) ) {
4962
+ let fields = self . parse_unspanned_seq (
4910
4963
& token:: OpenDelim ( token:: Paren ) ,
4911
4964
& token:: CloseDelim ( token:: Paren ) ,
4912
4965
seq_sep_trailing_allowed ( token:: Comma ) ,
4913
4966
|p| {
4914
- let attrs = p. parse_outer_attributes ( ) ;
4915
- let lo = p. span . lo ;
4916
- let struct_field_ = ast:: StructField_ {
4917
- kind : UnnamedField ( p. parse_visibility ( ) ) ,
4918
- id : ast:: DUMMY_NODE_ID ,
4919
- ty : p. parse_ty_sum ( ) ,
4920
- attrs : attrs,
4921
- } ;
4922
- spanned ( lo, p. span . hi , struct_field_)
4923
- } ) ;
4967
+ let attrs = p. parse_outer_attributes ( ) ;
4968
+ let lo = p. span . lo ;
4969
+ let struct_field_ = ast:: StructField_ {
4970
+ kind : UnnamedField ( p. parse_visibility ( ) ) ,
4971
+ id : ast:: DUMMY_NODE_ID ,
4972
+ ty : p. parse_ty_sum ( ) ,
4973
+ attrs : attrs,
4974
+ } ;
4975
+ spanned ( lo, p. span . hi , struct_field_)
4976
+ } ) ;
4977
+
4924
4978
if fields. len ( ) == 0 {
4925
4979
self . fatal ( format ! ( "unit-like struct definition should be \
4926
- written as `struct {};`",
4927
- token:: get_ident( class_name) ) [ ] ) ;
4980
+ written as `struct {};`",
4981
+ token:: get_ident( class_name. clone ( ) ) ) [ ] ) ;
4928
4982
}
4983
+
4984
+ self . parse_where_clause ( generics) ;
4929
4985
self . expect ( & token:: Semi ) ;
4930
- } else if self . eat ( & token:: Semi ) {
4931
- // It's a unit-like struct.
4932
- is_tuple_like = true ;
4933
- fields = Vec :: new ( ) ;
4986
+ fields
4987
+ // This is the case where we just see struct Foo<T> where T: Copy;
4988
+ } else if self . token . is_keyword ( keywords:: Where ) {
4989
+ self . parse_where_clause ( generics) ;
4990
+ self . expect ( & token:: Semi ) ;
4991
+ Vec :: new ( )
4992
+ // This case is where we see: `struct Foo<T>;`
4934
4993
} else {
4935
4994
let token_str = self . this_token_to_string ( ) ;
4936
- self . fatal ( format ! ( "expected `{}`, `(`, or `;` after struct \
4937
- name, found `{}`", "{" ,
4938
- token_str) [ ] )
4995
+ self . fatal ( format ! ( "expected `where`, `{}`, `(`, or `;` after struct \
4996
+ name, found `{}`", "{" , token_str) [ ] ) ;
4939
4997
}
4940
-
4941
- let _ = ast:: DUMMY_NODE_ID ; // FIXME: Workaround for crazy bug.
4942
- let new_id = ast:: DUMMY_NODE_ID ;
4943
- ( class_name,
4944
- ItemStruct ( P ( ast:: StructDef {
4945
- fields : fields,
4946
- ctor_id : if is_tuple_like { Some ( new_id) } else { None } ,
4947
- } ) , generics) ,
4948
- None )
4949
4998
}
4950
4999
4951
5000
/// Parse a structure field declaration
0 commit comments