From 0e660d8a79062ba3c664822a72ae782cb8c38da7 Mon Sep 17 00:00:00 2001 From: Janusz Marcinkiewicz Date: Sat, 23 Nov 2019 03:41:12 +0100 Subject: [PATCH] Add error reporting on nested keywords inside 'enum' definition --- src/librustc_parse/parser/item.rs | 37 ++++++++++++++++++++++++++++- src/test/ui/enum/nested-enum.rs | 8 +++++++ src/test/ui/enum/nested-enum.stderr | 26 ++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/enum/nested-enum.rs create mode 100644 src/test/ui/enum/nested-enum.stderr diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 13645e7144a9b..712715705e1ed 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -9,6 +9,7 @@ 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; @@ -16,7 +17,7 @@ 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::*; @@ -1341,6 +1342,10 @@ impl<'a> Parser<'a> { 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)) { @@ -1742,6 +1747,36 @@ 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 prev_token = self.token.clone(); + let item = self.parse_item()?; + if self.token == token::Comma { + self.bump(); + } + + let mut err = self.struct_span_err( + prev_token.span, + &format!("`{}` definition cannot be nested inside `{}`", pprust::token_to_string(&prev_token), keyword), + ); + err.span_suggestion( + item.unwrap().span, + &format!("consider creating a new `{}` definition instead of nesting", pprust::token_to_string(&prev_token)), + String::new(), + Applicability::MaybeIncorrect, + ); + err.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) -> P { P(Item { diff --git a/src/test/ui/enum/nested-enum.rs b/src/test/ui/enum/nested-enum.rs new file mode 100644 index 0000000000000..80957b8a14c23 --- /dev/null +++ b/src/test/ui/enum/nested-enum.rs @@ -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() { } diff --git a/src/test/ui/enum/nested-enum.stderr b/src/test/ui/enum/nested-enum.stderr new file mode 100644 index 0000000000000..7d6f57e88a826 --- /dev/null +++ b/src/test/ui/enum/nested-enum.stderr @@ -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 +