about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJanusz Marcinkiewicz <virrages@gmail.com>2019-11-23 03:41:12 +0100
committerJanusz Marcinkiewicz <virrages@gmail.com>2019-11-23 03:41:12 +0100
commit0e660d8a79062ba3c664822a72ae782cb8c38da7 (patch)
tree7f968a5aa46311dad16b9ae0acb968279720228f
parenta449535bbc7912c4adc1bbf2ab2738d0442f212c (diff)
downloadrust-0e660d8a79062ba3c664822a72ae782cb8c38da7.tar.gz
rust-0e660d8a79062ba3c664822a72ae782cb8c38da7.zip
Add error reporting on nested keywords inside 'enum' definition
-rw-r--r--src/librustc_parse/parser/item.rs37
-rw-r--r--src/test/ui/enum/nested-enum.rs8
-rw-r--r--src/test/ui/enum/nested-enum.stderr26
3 files changed, 70 insertions, 1 deletions
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 13645e7144a..712715705e1 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<Attribute>) -> P<Item> {
         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 00000000000..80957b8a14c
--- /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 00000000000..7d6f57e88a8
--- /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
+