about summary refs log tree commit diff
path: root/compiler/rustc_parse/src/parser
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-12-08 11:22:02 +0000
committerbors <bors@rust-lang.org>2021-12-08 11:22:02 +0000
commit4459e720bee5a741b962cfcd6f0593b32dc19009 (patch)
tree8f971851dcee5e588231ca5d7af66e223af47b08 /compiler/rustc_parse/src/parser
parentce0f7baf5651606c706b7014b5abdaa930cf2600 (diff)
parent90690dae69b5213fb04b88408ad4d18a7130f40c (diff)
downloadrust-4459e720bee5a741b962cfcd6f0593b32dc19009.tar.gz
rust-4459e720bee5a741b962cfcd6f0593b32dc19009.zip
Auto merge of #91656 - matthiaskrgr:rollup-lk96y6d, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #83744 (Deprecate crate_type and crate_name nested inside #![cfg_attr])
 - #90550 (Update certificates in some Ubuntu 16 images.)
 - #91272 (Print a suggestion when comparing references to primitive types in `const fn`)
 - #91467 (Emphasise that an OsStr[ing] is not necessarily a platform string)
 - #91531 (Do not add `;` to expected tokens list when it's wrong)
 - #91577 (Address some FIXMEs left over from #91475)
 - #91638 (Remove `in_band_lifetimes` from `rustc_mir_transform`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_parse/src/parser')
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs4
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs3
-rw-r--r--compiler/rustc_parse/src/parser/item.rs120
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs1
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs14
5 files changed, 113 insertions, 29 deletions
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index b402b8ba53a..ca92d6b7fd0 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -1,4 +1,4 @@
-use super::{AttrWrapper, Capturing, ForceCollect, Parser, PathStyle};
+use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
 use rustc_ast as ast;
 use rustc_ast::attr;
 use rustc_ast::token::{self, Nonterminal};
@@ -177,7 +177,7 @@ impl<'a> Parser<'a> {
             AttrWrapper::empty(),
             true,
             false,
-            |_| true,
+            FnParseMode { req_name: |_| true, req_body: true },
             ForceCollect::No,
         ) {
             Ok(Some(item)) => {
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 55af2c9ddd3..8e2e6eaee58 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1129,7 +1129,8 @@ impl<'a> Parser<'a> {
     }
 
     pub fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
-        if self.eat(&token::Semi) {
+        if self.token.kind == TokenKind::Semi {
+            self.bump();
             let mut err = self.struct_span_err(self.prev_token.span, "expected item, found `;`");
             err.span_suggestion_short(
                 self.prev_token.span,
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index cbeaf675be4..831c64e3faf 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -78,16 +78,17 @@ pub(super) type ItemInfo = (Ident, ItemKind);
 
 impl<'a> Parser<'a> {
     pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<P<Item>>> {
-        self.parse_item_(|_| true, force_collect).map(|i| i.map(P))
+        let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
+        self.parse_item_(fn_parse_mode, force_collect).map(|i| i.map(P))
     }
 
     fn parse_item_(
         &mut self,
-        req_name: ReqName,
+        fn_parse_mode: FnParseMode,
         force_collect: ForceCollect,
     ) -> PResult<'a, Option<Item>> {
         let attrs = self.parse_outer_attributes()?;
-        self.parse_item_common(attrs, true, false, req_name, force_collect)
+        self.parse_item_common(attrs, true, false, fn_parse_mode, force_collect)
     }
 
     pub(super) fn parse_item_common(
@@ -95,7 +96,7 @@ impl<'a> Parser<'a> {
         attrs: AttrWrapper,
         mac_allowed: bool,
         attrs_allowed: bool,
-        req_name: ReqName,
+        fn_parse_mode: FnParseMode,
         force_collect: ForceCollect,
     ) -> PResult<'a, Option<Item>> {
         // Don't use `maybe_whole` so that we have precise control
@@ -113,7 +114,8 @@ impl<'a> Parser<'a> {
         let mut unclosed_delims = vec![];
         let item =
             self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| {
-                let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name);
+                let item =
+                    this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode);
                 unclosed_delims.append(&mut this.unclosed_delims);
                 Ok((item?, TrailingToken::None))
             })?;
@@ -127,12 +129,13 @@ impl<'a> Parser<'a> {
         mut attrs: Vec<Attribute>,
         mac_allowed: bool,
         attrs_allowed: bool,
-        req_name: ReqName,
+        fn_parse_mode: FnParseMode,
     ) -> PResult<'a, Option<Item>> {
         let lo = self.token.span;
         let vis = self.parse_visibility(FollowedByType::No)?;
         let mut def = self.parse_defaultness();
-        let kind = self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, req_name)?;
+        let kind =
+            self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, fn_parse_mode)?;
         if let Some((ident, kind)) = kind {
             self.error_on_unconsumed_default(def, &kind);
             let span = lo.to(self.prev_token.span);
@@ -192,7 +195,7 @@ impl<'a> Parser<'a> {
         lo: Span,
         vis: &Visibility,
         def: &mut Defaultness,
-        req_name: ReqName,
+        fn_parse_mode: FnParseMode,
     ) -> PResult<'a, Option<ItemInfo>> {
         let def_final = def == &Defaultness::Final;
         let mut def = || mem::replace(def, Defaultness::Final);
@@ -219,7 +222,7 @@ impl<'a> Parser<'a> {
             (Ident::empty(), ItemKind::Use(tree))
         } else if self.check_fn_front_matter(def_final) {
             // FUNCTION ITEM
-            let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?;
+            let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo)?;
             (ident, ItemKind::Fn(Box::new(Fn { defaultness: def(), sig, generics, body })))
         } else if self.eat_keyword(kw::Extern) {
             if self.eat_keyword(kw::Crate) {
@@ -733,23 +736,26 @@ impl<'a> Parser<'a> {
         &mut self,
         force_collect: ForceCollect,
     ) -> PResult<'a, Option<Option<P<AssocItem>>>> {
-        self.parse_assoc_item(|_| true, force_collect)
+        let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
+        self.parse_assoc_item(fn_parse_mode, force_collect)
     }
 
     pub fn parse_trait_item(
         &mut self,
         force_collect: ForceCollect,
     ) -> PResult<'a, Option<Option<P<AssocItem>>>> {
-        self.parse_assoc_item(|edition| edition >= Edition::Edition2018, force_collect)
+        let fn_parse_mode =
+            FnParseMode { req_name: |edition| edition >= Edition::Edition2018, req_body: false };
+        self.parse_assoc_item(fn_parse_mode, force_collect)
     }
 
     /// Parses associated items.
     fn parse_assoc_item(
         &mut self,
-        req_name: ReqName,
+        fn_parse_mode: FnParseMode,
         force_collect: ForceCollect,
     ) -> PResult<'a, Option<Option<P<AssocItem>>>> {
-        Ok(self.parse_item_(req_name, force_collect)?.map(
+        Ok(self.parse_item_(fn_parse_mode, force_collect)?.map(
             |Item { attrs, id, span, vis, ident, kind, tokens }| {
                 let kind = match AssocItemKind::try_from(kind) {
                     Ok(kind) => kind,
@@ -944,7 +950,8 @@ impl<'a> Parser<'a> {
         &mut self,
         force_collect: ForceCollect,
     ) -> PResult<'a, Option<Option<P<ForeignItem>>>> {
-        Ok(self.parse_item_(|_| true, force_collect)?.map(
+        let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: false };
+        Ok(self.parse_item_(fn_parse_mode, force_collect)?.map(
             |Item { attrs, id, span, vis, ident, kind, tokens }| {
                 let kind = match ForeignItemKind::try_from(kind) {
                     Ok(kind) => kind,
@@ -1484,7 +1491,8 @@ impl<'a> Parser<'a> {
         if !is_raw && ident.is_reserved() {
             let err = if self.check_fn_front_matter(false) {
                 // We use `parse_fn` to get a span for the function
-                if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) {
+                let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
+                if let Err(mut db) = self.parse_fn(&mut Vec::new(), fn_parse_mode, lo) {
                     db.delay_as_bug();
                 }
                 let mut err = self.struct_span_err(
@@ -1698,25 +1706,82 @@ impl<'a> Parser<'a> {
 /// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
 ///
 /// The function decides if, per-parameter `p`, `p` must have a pattern or just a type.
+///
+/// This function pointer accepts an edition, because in edition 2015, trait declarations
+/// were allowed to omit parameter names. In 2018, they became required.
 type ReqName = fn(Edition) -> bool;
 
+/// Parsing configuration for functions.
+///
+/// The syntax of function items is slightly different within trait definitions,
+/// impl blocks, and modules. It is still parsed using the same code, just with
+/// different flags set, so that even when the input is wrong and produces a parse
+/// error, it still gets into the AST and the rest of the parser and
+/// type checker can run.
+#[derive(Clone, Copy)]
+pub(crate) struct FnParseMode {
+    /// A function pointer that decides if, per-parameter `p`, `p` must have a
+    /// pattern or just a type. This field affects parsing of the parameters list.
+    ///
+    /// ```text
+    /// fn foo(alef: A) -> X { X::new() }
+    ///        -----^^ affects parsing this part of the function signature
+    ///        |
+    ///        if req_name returns false, then this name is optional
+    ///
+    /// fn bar(A) -> X;
+    ///        ^
+    ///        |
+    ///        if req_name returns true, this is an error
+    /// ```
+    ///
+    /// Calling this function pointer should only return false if:
+    ///
+    ///   * The item is being parsed inside of a trait definition.
+    ///     Within an impl block or a module, it should always evaluate
+    ///     to true.
+    ///   * The span is from Edition 2015. In particular, you can get a
+    ///     2015 span inside a 2021 crate using macros.
+    pub req_name: ReqName,
+    /// If this flag is set to `true`, then plain, semicolon-terminated function
+    /// prototypes are not allowed here.
+    ///
+    /// ```text
+    /// fn foo(alef: A) -> X { X::new() }
+    ///                      ^^^^^^^^^^^^
+    ///                      |
+    ///                      this is always allowed
+    ///
+    /// fn bar(alef: A, bet: B) -> X;
+    ///                             ^
+    ///                             |
+    ///                             if req_body is set to true, this is an error
+    /// ```
+    ///
+    /// This field should only be set to false if the item is inside of a trait
+    /// definition or extern block. Within an impl block or a module, it should
+    /// always be set to true.
+    pub req_body: bool,
+}
+
 /// Parsing of functions and methods.
 impl<'a> Parser<'a> {
     /// Parse a function starting from the front matter (`const ...`) to the body `{ ... }` or `;`.
     fn parse_fn(
         &mut self,
         attrs: &mut Vec<Attribute>,
-        req_name: ReqName,
+        fn_parse_mode: FnParseMode,
         sig_lo: Span,
     ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
         let header = self.parse_fn_front_matter()?; // `const ... fn`
         let ident = self.parse_ident()?; // `foo`
         let mut generics = self.parse_generics()?; // `<'a, T, ...>`
-        let decl = self.parse_fn_decl(req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)`
+        let decl =
+            self.parse_fn_decl(fn_parse_mode.req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)`
         generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
 
         let mut sig_hi = self.prev_token.span;
-        let body = self.parse_fn_body(attrs, &ident, &mut sig_hi)?; // `;` or `{ ... }`.
+        let body = self.parse_fn_body(attrs, &ident, &mut sig_hi, fn_parse_mode.req_body)?; // `;` or `{ ... }`.
         let fn_sig_span = sig_lo.to(sig_hi);
         Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body))
     }
@@ -1729,9 +1794,17 @@ impl<'a> Parser<'a> {
         attrs: &mut Vec<Attribute>,
         ident: &Ident,
         sig_hi: &mut Span,
+        req_body: bool,
     ) -> PResult<'a, Option<P<Block>>> {
-        let (inner_attrs, body) = if self.eat(&token::Semi) {
+        let has_semi = if req_body {
+            self.token.kind == TokenKind::Semi
+        } else {
+            // Only include `;` in list of expected tokens if body is not required
+            self.check(&TokenKind::Semi)
+        };
+        let (inner_attrs, body) = if has_semi {
             // Include the trailing semicolon in the span of the signature
+            self.expect_semi()?;
             *sig_hi = self.prev_token.span;
             (Vec::new(), None)
         } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
@@ -1752,9 +1825,12 @@ impl<'a> Parser<'a> {
                 .emit();
             (Vec::new(), Some(self.mk_block_err(span)))
         } else {
-            if let Err(mut err) =
-                self.expected_one_of_not_found(&[], &[token::Semi, token::OpenDelim(token::Brace)])
-            {
+            let expected = if req_body {
+                &[token::OpenDelim(token::Brace)][..]
+            } else {
+                &[token::Semi, token::OpenDelim(token::Brace)]
+            };
+            if let Err(mut err) = self.expected_one_of_not_found(&[], &expected) {
                 if self.token.kind == token::CloseDelim(token::Brace) {
                     // The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
                     // the AST for typechecking.
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 9212aaa87d1..6d534bece46 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -14,6 +14,7 @@ use crate::lexer::UnmatchedBrace;
 pub use attr_wrapper::AttrWrapper;
 pub use diagnostics::AttemptLocalParseRecovery;
 use diagnostics::Error;
+pub(crate) use item::FnParseMode;
 pub use pat::{RecoverColon, RecoverComma};
 pub use path::PathStyle;
 
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 01e751ea8b5..d3e7d1690cc 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -4,7 +4,9 @@ use super::expr::LhsExpr;
 use super::pat::RecoverComma;
 use super::path::PathStyle;
 use super::TrailingToken;
-use super::{AttrWrapper, BlockMode, ForceCollect, Parser, Restrictions, SemiColonMode};
+use super::{
+    AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode,
+};
 use crate::maybe_whole;
 
 use rustc_ast as ast;
@@ -79,9 +81,13 @@ impl<'a> Parser<'a> {
             } else {
                 self.parse_stmt_path_start(lo, attrs)
             }?
-        } else if let Some(item) =
-            self.parse_item_common(attrs.clone(), false, true, |_| true, force_collect)?
-        {
+        } else if let Some(item) = self.parse_item_common(
+            attrs.clone(),
+            false,
+            true,
+            FnParseMode { req_name: |_| true, req_body: true },
+            force_collect,
+        )? {
             // FIXME: Bad copy of attrs
             self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
         } else if self.eat(&token::Semi) {