Skip to content

Commit

Permalink
Rollup merge of rust-lang#66641 - VirrageS:master, r=Centril
Browse files Browse the repository at this point in the history
parser: recover on nested ADTs as enum variants

Closes: rust-lang#66127
  • Loading branch information
Centril authored Nov 24, 2019
2 parents a3ff52c + 9300c3b commit 980ccaa
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 1 deletion.
36 changes: 35 additions & 1 deletion src/librustc_parse/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness
use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind};
use syntax::ast::{Ty, TyKind, Generics, TraitRef, EnumDef, VariantData, StructField};
use syntax::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, FnSig, SelfKind, Param};
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::ThinVec;
use syntax::token;
use syntax::tokenstream::{TokenTree, TokenStream};
use syntax::source_map::{self, respan, Span};
use syntax::struct_span_err;
use syntax_pos::BytePos;
use syntax_pos::symbol::{kw, sym};
use syntax_pos::symbol::{kw, sym, Symbol};

use rustc_error_codes::*;

Expand Down Expand Up @@ -1336,11 +1337,17 @@ impl<'a> Parser<'a> {
/// Parses the part of an enum declaration following the `{`.
fn parse_enum_def(&mut self, _generics: &Generics) -> PResult<'a, EnumDef> {
let mut variants = Vec::new();
// FIXME: Consider using `parse_delim_comma_seq`.
// We could then remove eating comma in `recover_nested_adt_item`.
while self.token != token::CloseDelim(token::Brace) {
let variant_attrs = self.parse_outer_attributes()?;
let vlo = self.token.span;

let vis = self.parse_visibility(FollowedByType::No)?;
if !self.recover_nested_adt_item(kw::Enum)? {
// Item already parsed, we need to skip this variant.
continue
}
let ident = self.parse_ident()?;

let struct_def = if self.check(&token::OpenDelim(token::Brace)) {
Expand Down Expand Up @@ -1742,6 +1749,33 @@ impl<'a> Parser<'a> {
).emit();
}

/// Checks if current token is one of tokens which cannot be nested like `kw::Enum`. In case
/// it is, we try to parse the item and report error about nested types.
fn recover_nested_adt_item(&mut self, keyword: Symbol) -> PResult<'a, bool> {
if self.token.is_keyword(kw::Enum) ||
self.token.is_keyword(kw::Struct) ||
self.token.is_keyword(kw::Union)
{
let kw_token = self.token.clone();
let kw_str = pprust::token_to_string(&kw_token);
let item = self.parse_item()?;
self.eat(&token::Comma);

self.struct_span_err(
kw_token.span,
&format!("`{}` definition cannot be nested inside `{}`", kw_str, keyword),
).span_suggestion(
item.unwrap().span,
&format!("consider creating a new `{}` definition instead of nesting", kw_str),
String::new(),
Applicability::MaybeIncorrect,
).emit();
// We successfully parsed the item but we must inform the caller about nested problem.
return Ok(false)
}
Ok(true)
}

fn mk_item(&self, span: Span, ident: Ident, kind: ItemKind, vis: Visibility,
attrs: Vec<Attribute>) -> P<Item> {
P(Item {
Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/enum/nested-enum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
enum Foo {
enum Bar { Baz }, //~ ERROR `enum` definition cannot be nested inside `enum`
struct Quux { field: u8 }, //~ ERROR `struct` definition cannot be nested inside `enum`
union Wibble { field: u8 }, //~ ERROR `union` definition cannot be nested inside `enum`
Bat,
}

fn main() { }
26 changes: 26 additions & 0 deletions src/test/ui/enum/nested-enum.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
error: `enum` definition cannot be nested inside `enum`
--> $DIR/nested-enum.rs:2:5
|
LL | enum Bar { Baz },
| ^^^^------------
| |
| help: consider creating a new `enum` definition instead of nesting

error: `struct` definition cannot be nested inside `enum`
--> $DIR/nested-enum.rs:3:5
|
LL | struct Quux { field: u8 },
| ^^^^^^-------------------
| |
| help: consider creating a new `struct` definition instead of nesting

error: `union` definition cannot be nested inside `enum`
--> $DIR/nested-enum.rs:4:5
|
LL | union Wibble { field: u8 },
| ^^^^^---------------------
| |
| help: consider creating a new `union` definition instead of nesting

error: aborting due to 3 previous errors

0 comments on commit 980ccaa

Please sign in to comment.