Skip to content

Commit 980ccaa

Browse files
authored
Rollup merge of #66641 - VirrageS:master, r=Centril
parser: recover on nested ADTs as enum variants Closes: #66127
2 parents a3ff52c + 9300c3b commit 980ccaa

File tree

3 files changed

+69
-1
lines changed

3 files changed

+69
-1
lines changed

src/librustc_parse/parser/item.rs

+35-1
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness
99
use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind};
1010
use syntax::ast::{Ty, TyKind, Generics, TraitRef, EnumDef, VariantData, StructField};
1111
use syntax::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, FnSig, SelfKind, Param};
12+
use syntax::print::pprust;
1213
use syntax::ptr::P;
1314
use syntax::ThinVec;
1415
use syntax::token;
1516
use syntax::tokenstream::{TokenTree, TokenStream};
1617
use syntax::source_map::{self, respan, Span};
1718
use syntax::struct_span_err;
1819
use syntax_pos::BytePos;
19-
use syntax_pos::symbol::{kw, sym};
20+
use syntax_pos::symbol::{kw, sym, Symbol};
2021

2122
use 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 {

src/test/ui/enum/nested-enum.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
enum Foo {
2+
enum Bar { Baz }, //~ ERROR `enum` definition cannot be nested inside `enum`
3+
struct Quux { field: u8 }, //~ ERROR `struct` definition cannot be nested inside `enum`
4+
union Wibble { field: u8 }, //~ ERROR `union` definition cannot be nested inside `enum`
5+
Bat,
6+
}
7+
8+
fn main() { }

src/test/ui/enum/nested-enum.stderr

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: `enum` definition cannot be nested inside `enum`
2+
--> $DIR/nested-enum.rs:2:5
3+
|
4+
LL | enum Bar { Baz },
5+
| ^^^^------------
6+
| |
7+
| help: consider creating a new `enum` definition instead of nesting
8+
9+
error: `struct` definition cannot be nested inside `enum`
10+
--> $DIR/nested-enum.rs:3:5
11+
|
12+
LL | struct Quux { field: u8 },
13+
| ^^^^^^-------------------
14+
| |
15+
| help: consider creating a new `struct` definition instead of nesting
16+
17+
error: `union` definition cannot be nested inside `enum`
18+
--> $DIR/nested-enum.rs:4:5
19+
|
20+
LL | union Wibble { field: u8 },
21+
| ^^^^^---------------------
22+
| |
23+
| help: consider creating a new `union` definition instead of nesting
24+
25+
error: aborting due to 3 previous errors
26+

0 commit comments

Comments
 (0)