@@ -9,14 +9,15 @@ use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness
99use syntax:: ast:: { Visibility , VisibilityKind , Mutability , FnHeader , ForeignItem , ForeignItemKind } ;
1010use syntax:: ast:: { Ty , TyKind , Generics , TraitRef , EnumDef , VariantData , StructField } ;
1111use syntax:: ast:: { Mac , MacDelimiter , Block , BindingMode , FnDecl , FnSig , SelfKind , Param } ;
12+ use syntax:: print:: pprust;
1213use syntax:: ptr:: P ;
1314use syntax:: ThinVec ;
1415use syntax:: token;
1516use syntax:: tokenstream:: { TokenTree , TokenStream } ;
1617use syntax:: source_map:: { self , respan, Span } ;
1718use syntax:: struct_span_err;
1819use syntax_pos:: BytePos ;
19- use syntax_pos:: symbol:: { kw, sym} ;
20+ use syntax_pos:: symbol:: { kw, sym, Symbol } ;
2021
2122use rustc_error_codes:: * ;
2223
@@ -1336,11 +1337,17 @@ impl<'a> Parser<'a> {
13361337 /// Parses the part of an enum declaration following the `{`.
13371338 fn parse_enum_def ( & mut self , _generics : & Generics ) -> PResult < ' a , EnumDef > {
13381339 let mut variants = Vec :: new ( ) ;
1340+ // FIXME: Consider using `parse_delim_comma_seq`.
1341+ // We could then remove eating comma in `recover_nested_adt_item`.
13391342 while self . token != token:: CloseDelim ( token:: Brace ) {
13401343 let variant_attrs = self . parse_outer_attributes ( ) ?;
13411344 let vlo = self . token . span ;
13421345
13431346 let vis = self . parse_visibility ( FollowedByType :: No ) ?;
1347+ if !self . recover_nested_adt_item ( kw:: Enum ) ? {
1348+ // Item already parsed, we need to skip this variant.
1349+ continue
1350+ }
13441351 let ident = self . parse_ident ( ) ?;
13451352
13461353 let struct_def = if self . check ( & token:: OpenDelim ( token:: Brace ) ) {
@@ -1742,6 +1749,33 @@ impl<'a> Parser<'a> {
17421749 ) . emit ( ) ;
17431750 }
17441751
1752+ /// Checks if current token is one of tokens which cannot be nested like `kw::Enum`. In case
1753+ /// it is, we try to parse the item and report error about nested types.
1754+ fn recover_nested_adt_item ( & mut self , keyword : Symbol ) -> PResult < ' a , bool > {
1755+ if self . token . is_keyword ( kw:: Enum ) ||
1756+ self . token . is_keyword ( kw:: Struct ) ||
1757+ self . token . is_keyword ( kw:: Union )
1758+ {
1759+ let kw_token = self . token . clone ( ) ;
1760+ let kw_str = pprust:: token_to_string ( & kw_token) ;
1761+ let item = self . parse_item ( ) ?;
1762+ self . eat ( & token:: Comma ) ;
1763+
1764+ self . struct_span_err (
1765+ kw_token. span ,
1766+ & format ! ( "`{}` definition cannot be nested inside `{}`" , kw_str, keyword) ,
1767+ ) . span_suggestion (
1768+ item. unwrap ( ) . span ,
1769+ & format ! ( "consider creating a new `{}` definition instead of nesting" , kw_str) ,
1770+ String :: new ( ) ,
1771+ Applicability :: MaybeIncorrect ,
1772+ ) . emit ( ) ;
1773+ // We successfully parsed the item but we must inform the caller about nested problem.
1774+ return Ok ( false )
1775+ }
1776+ Ok ( true )
1777+ }
1778+
17451779 fn mk_item ( & self , span : Span , ident : Ident , kind : ItemKind , vis : Visibility ,
17461780 attrs : Vec < Attribute > ) -> P < Item > {
17471781 P ( Item {
0 commit comments