about summary refs log tree commit diff
path: root/compiler/rustc_parse/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src')
-rw-r--r--compiler/rustc_parse/src/parser/item.rs52
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs36
2 files changed, 58 insertions, 30 deletions
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index acf3867cf89..20e8b0f6425 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1124,11 +1124,11 @@ impl<'a> Parser<'a> {
                 if !this.recover_nested_adt_item(kw::Enum)? {
                     return Ok((None, TrailingToken::None));
                 }
-                let ident = this.parse_ident()?;
+                let ident = this.parse_field_ident("enum", vlo)?;
 
                 let struct_def = if this.check(&token::OpenDelim(token::Brace)) {
                     // Parse a struct variant.
-                    let (fields, recovered) = this.parse_record_struct_body()?;
+                    let (fields, recovered) = this.parse_record_struct_body("struct")?;
                     VariantData::Struct(fields, recovered)
                 } else if this.check(&token::OpenDelim(token::Paren)) {
                     VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID)
@@ -1182,7 +1182,7 @@ impl<'a> Parser<'a> {
                 VariantData::Unit(DUMMY_NODE_ID)
             } else {
                 // If we see: `struct Foo<T> where T: Copy { ... }`
-                let (fields, recovered) = self.parse_record_struct_body()?;
+                let (fields, recovered) = self.parse_record_struct_body("struct")?;
                 VariantData::Struct(fields, recovered)
             }
         // No `where` so: `struct Foo<T>;`
@@ -1190,7 +1190,7 @@ impl<'a> Parser<'a> {
             VariantData::Unit(DUMMY_NODE_ID)
         // Record-style struct definition
         } else if self.token == token::OpenDelim(token::Brace) {
-            let (fields, recovered) = self.parse_record_struct_body()?;
+            let (fields, recovered) = self.parse_record_struct_body("struct")?;
             VariantData::Struct(fields, recovered)
         // Tuple-style struct definition with optional where-clause.
         } else if self.token == token::OpenDelim(token::Paren) {
@@ -1220,10 +1220,10 @@ impl<'a> Parser<'a> {
 
         let vdata = if self.token.is_keyword(kw::Where) {
             generics.where_clause = self.parse_where_clause()?;
-            let (fields, recovered) = self.parse_record_struct_body()?;
+            let (fields, recovered) = self.parse_record_struct_body("union")?;
             VariantData::Struct(fields, recovered)
         } else if self.token == token::OpenDelim(token::Brace) {
-            let (fields, recovered) = self.parse_record_struct_body()?;
+            let (fields, recovered) = self.parse_record_struct_body("union")?;
             VariantData::Struct(fields, recovered)
         } else {
             let token_str = super::token_descr(&self.token);
@@ -1236,12 +1236,15 @@ impl<'a> Parser<'a> {
         Ok((class_name, ItemKind::Union(vdata, generics)))
     }
 
-    fn parse_record_struct_body(&mut self) -> PResult<'a, (Vec<FieldDef>, /* recovered */ bool)> {
+    fn parse_record_struct_body(
+        &mut self,
+        adt_ty: &str,
+    ) -> PResult<'a, (Vec<FieldDef>, /* recovered */ bool)> {
         let mut fields = Vec::new();
         let mut recovered = false;
         if self.eat(&token::OpenDelim(token::Brace)) {
             while self.token != token::CloseDelim(token::Brace) {
-                let field = self.parse_field_def().map_err(|e| {
+                let field = self.parse_field_def(adt_ty).map_err(|e| {
                     self.consume_block(token::Brace, ConsumeClosingDelim::No);
                     recovered = true;
                     e
@@ -1294,24 +1297,25 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses an element of a struct declaration.
-    fn parse_field_def(&mut self) -> PResult<'a, FieldDef> {
+    fn parse_field_def(&mut self, adt_ty: &str) -> PResult<'a, FieldDef> {
         let attrs = self.parse_outer_attributes()?;
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let lo = this.token.span;
             let vis = this.parse_visibility(FollowedByType::No)?;
-            Ok((this.parse_single_struct_field(lo, vis, attrs)?, TrailingToken::None))
+            Ok((this.parse_single_struct_field(adt_ty, lo, vis, attrs)?, TrailingToken::None))
         })
     }
 
     /// Parses a structure field declaration.
     fn parse_single_struct_field(
         &mut self,
+        adt_ty: &str,
         lo: Span,
         vis: Visibility,
         attrs: Vec<Attribute>,
     ) -> PResult<'a, FieldDef> {
         let mut seen_comma: bool = false;
-        let a_var = self.parse_name_and_ty(lo, vis, attrs)?;
+        let a_var = self.parse_name_and_ty(adt_ty, lo, vis, attrs)?;
         if self.token == token::Comma {
             seen_comma = true;
         }
@@ -1398,11 +1402,12 @@ impl<'a> Parser<'a> {
     /// Parses a structure field.
     fn parse_name_and_ty(
         &mut self,
+        adt_ty: &str,
         lo: Span,
         vis: Visibility,
         attrs: Vec<Attribute>,
     ) -> PResult<'a, FieldDef> {
-        let name = self.parse_ident_common(false)?;
+        let name = self.parse_field_ident(adt_ty, lo)?;
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
         Ok(FieldDef {
@@ -1416,6 +1421,29 @@ impl<'a> Parser<'a> {
         })
     }
 
+    /// Parses a field identifier. Specialized version of `parse_ident_common`
+    /// for better diagnostics and suggestions.
+    fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
+        let (ident, is_raw) = self.ident_or_err()?;
+        if !is_raw && ident.is_reserved() {
+            let err = if self.check_fn_front_matter(false) {
+                let _ = self.parse_fn(&mut Vec::new(), |_| true, lo);
+                let mut err = self.struct_span_err(
+                    lo.to(self.prev_token.span),
+                    &format!("functions are not allowed in {} definitions", adt_ty),
+                );
+                err.help("unlike in C++, Java, and C#, functions are declared in `impl` blocks");
+                err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
+                err
+            } else {
+                self.expected_ident_found()
+            };
+            return Err(err);
+        }
+        self.bump();
+        Ok(ident)
+    }
+
     /// Parses a declarative macro 2.0 definition.
     /// The `macro` keyword has already been parsed.
     /// ```
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index ed95a5661b1..74481e236f3 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -522,27 +522,27 @@ impl<'a> Parser<'a> {
         self.parse_ident_common(true)
     }
 
+    fn ident_or_err(&mut self) -> PResult<'a, (Ident, /* is_raw */ bool)> {
+        self.token.ident().ok_or_else(|| match self.prev_token.kind {
+            TokenKind::DocComment(..) => {
+                self.span_fatal_err(self.prev_token.span, Error::UselessDocComment)
+            }
+            _ => self.expected_ident_found(),
+        })
+    }
+
     fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> {
-        match self.token.ident() {
-            Some((ident, is_raw)) => {
-                if !is_raw && ident.is_reserved() {
-                    let mut err = self.expected_ident_found();
-                    if recover {
-                        err.emit();
-                    } else {
-                        return Err(err);
-                    }
-                }
-                self.bump();
-                Ok(ident)
+        let (ident, is_raw) = self.ident_or_err()?;
+        if !is_raw && ident.is_reserved() {
+            let mut err = self.expected_ident_found();
+            if recover {
+                err.emit();
+            } else {
+                return Err(err);
             }
-            _ => Err(match self.prev_token.kind {
-                TokenKind::DocComment(..) => {
-                    self.span_fatal_err(self.prev_token.span, Error::UselessDocComment)
-                }
-                _ => self.expected_ident_found(),
-            }),
         }
+        self.bump();
+        Ok(ident)
     }
 
     /// Checks if the next token is `tok`, and returns `true` if so.