use crate::errors::{DocCommentDoesNotDocumentAnything, UseEmptyBlockNotSemi}; use super::diagnostics::{dummy_arg, ConsumeClosingDelim}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken}; use crate::errors::FnTypoWithImpl; use rustc_ast::ast::*; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::util::case::Case; use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID}; use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind}; use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind}; use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, VariantData}; use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind}; use rustc_ast::{MacCall, MacDelimiter}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, IntoDiagnostic, PResult, StashKey}; use rustc_span::edition::Edition; use rustc_span::lev_distance::lev_distance; use rustc_span::source_map::{self, Span}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::DUMMY_SP; use std::mem; use thin_vec::ThinVec; impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main entry point for the parser. pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> { let (attrs, items, spans) = self.parse_mod(&token::Eof)?; Ok(ast::Crate { attrs, items, spans, id: DUMMY_NODE_ID, is_placeholder: false }) } /// Parses a `mod { ... }` or `mod ;` item. fn parse_item_mod(&mut self, attrs: &mut AttrVec) -> PResult<'a, ItemInfo> { let unsafety = self.parse_unsafety(Case::Sensitive); self.expect_keyword(kw::Mod)?; let id = self.parse_ident()?; let mod_kind = if self.eat(&token::Semi) { ModKind::Unloaded } else { self.expect(&token::OpenDelim(Delimiter::Brace))?; let (inner_attrs, items, inner_span) = self.parse_mod(&token::CloseDelim(Delimiter::Brace))?; attrs.extend(inner_attrs); ModKind::Loaded(items, Inline::Yes, inner_span) }; Ok((id, ItemKind::Mod(unsafety, mod_kind))) } /// Parses the contents of a module (inner attributes followed by module items). pub fn parse_mod( &mut self, term: &TokenKind, ) -> PResult<'a, (AttrVec, Vec>, ModSpans)> { let lo = self.token.span; let attrs = self.parse_inner_attributes()?; let post_attr_lo = self.token.span; let mut items = vec![]; while let Some(item) = self.parse_item(ForceCollect::No)? { items.push(item); self.maybe_consume_incorrect_semicolon(&items); } if !self.eat(term) { let token_str = super::token_descr(&self.token); if !self.maybe_consume_incorrect_semicolon(&items) { let msg = &format!("expected item, found {token_str}"); let mut err = self.struct_span_err(self.token.span, msg); let label = if self.is_kw_followed_by_ident(kw::Let) { "consider using `const` or `static` instead of `let` for global variables" } else { "expected item" }; err.span_label(self.token.span, label); return Err(err); } } let inject_use_span = post_attr_lo.data().with_hi(post_attr_lo.lo()); let mod_spans = ModSpans { inner_span: lo.to(self.prev_token.span), inject_use_span }; Ok((attrs, items, mod_spans)) } } pub(super) type ItemInfo = (Ident, ItemKind); impl<'a> Parser<'a> { pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option>> { 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, fn_parse_mode: FnParseMode, force_collect: ForceCollect, ) -> PResult<'a, Option> { self.recover_diff_marker(); let attrs = self.parse_outer_attributes()?; self.recover_diff_marker(); self.parse_item_common(attrs, true, false, fn_parse_mode, force_collect) } pub(super) fn parse_item_common( &mut self, attrs: AttrWrapper, mac_allowed: bool, attrs_allowed: bool, fn_parse_mode: FnParseMode, force_collect: ForceCollect, ) -> PResult<'a, Option> { // Don't use `maybe_whole` so that we have precise control // over when we bump the parser if let token::Interpolated(nt) = &self.token.kind && let token::NtItem(item) = &**nt { let mut item = item.clone(); self.bump(); attrs.prepend_to_nt_inner(&mut item.attrs); return Ok(Some(item.into_inner())); }; 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, fn_parse_mode); unclosed_delims.append(&mut this.unclosed_delims); Ok((item?, TrailingToken::None)) })?; self.unclosed_delims.append(&mut unclosed_delims); Ok(item) } fn parse_item_common_( &mut self, mut attrs: AttrVec, mac_allowed: bool, attrs_allowed: bool, fn_parse_mode: FnParseMode, ) -> PResult<'a, Option> { 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, fn_parse_mode, Case::Sensitive, )?; if let Some((ident, kind)) = kind { self.error_on_unconsumed_default(def, &kind); let span = lo.to(self.prev_token.span); let id = DUMMY_NODE_ID; let item = Item { ident, attrs, id, kind, vis, span, tokens: None }; return Ok(Some(item)); } // At this point, we have failed to parse an item. self.error_on_unmatched_vis(&vis); self.error_on_unmatched_defaultness(def); if !attrs_allowed { self.recover_attrs_no_item(&attrs)?; } Ok(None) } /// Error in-case a non-inherited visibility was parsed but no item followed. fn error_on_unmatched_vis(&self, vis: &Visibility) { if let VisibilityKind::Inherited = vis.kind { return; } let vs = pprust::vis_to_string(&vis); let vs = vs.trim_end(); self.struct_span_err(vis.span, &format!("visibility `{vs}` is not followed by an item")) .span_label(vis.span, "the visibility") .help(&format!("you likely meant to define an item, e.g., `{vs} fn foo() {{}}`")) .emit(); } /// Error in-case a `default` was parsed but no item followed. fn error_on_unmatched_defaultness(&self, def: Defaultness) { if let Defaultness::Default(sp) = def { self.struct_span_err(sp, "`default` is not followed by an item") .span_label(sp, "the `default` qualifier") .note("only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`") .emit(); } } /// Error in-case `default` was parsed in an in-appropriate context. fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) { if let Defaultness::Default(span) = def { let msg = format!("{} {} cannot be `default`", kind.article(), kind.descr()); self.struct_span_err(span, &msg) .span_label(span, "`default` because of this") .note("only associated `fn`, `const`, and `type` items can be `default`") .emit(); } } /// Parses one of the items allowed by the flags. fn parse_item_kind( &mut self, attrs: &mut AttrVec, macros_allowed: bool, lo: Span, vis: &Visibility, def: &mut Defaultness, fn_parse_mode: FnParseMode, case: Case, ) -> PResult<'a, Option> { let def_final = def == &Defaultness::Final; let mut def_ = || mem::replace(def, Defaultness::Final); let info = if self.eat_keyword_case(kw::Use, case) { self.parse_use_item()? } else if self.check_fn_front_matter(def_final, case) { // FUNCTION ITEM let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?; (ident, ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, body }))) } else if self.eat_keyword(kw::Extern) { if self.eat_keyword(kw::Crate) { // EXTERN CRATE self.parse_item_extern_crate()? } else { // EXTERN BLOCK self.parse_item_foreign_mod(attrs, Unsafe::No)? } } else if self.is_unsafe_foreign_mod() { // EXTERN BLOCK let unsafety = self.parse_unsafety(Case::Sensitive); self.expect_keyword(kw::Extern)?; self.parse_item_foreign_mod(attrs, unsafety)? } else if self.is_static_global() { // STATIC ITEM self.bump(); // `static` let m = self.parse_mutability(); let (ident, ty, expr) = self.parse_item_global(Some(m))?; (ident, ItemKind::Static(ty, m, expr)) } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM if self.token.is_keyword(kw::Impl) { // recover from `const impl`, suggest `impl const` self.recover_const_impl(const_span, attrs, def_())? } else { self.recover_const_mut(const_span); let (ident, ty, expr) = self.parse_item_global(None)?; (ident, ItemKind::Const(def_(), ty, expr)) } } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() { // TRAIT ITEM self.parse_item_trait(attrs, lo)? } else if self.check_keyword(kw::Impl) || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Impl]) { // IMPL ITEM self.parse_item_impl(attrs, def_())? } else if self.check_keyword(kw::Mod) || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Mod]) { // MODULE ITEM self.parse_item_mod(attrs)? } else if self.eat_keyword(kw::Type) { // TYPE ITEM self.parse_type_alias(def_())? } else if self.eat_keyword(kw::Enum) { // ENUM ITEM self.parse_item_enum()? } else if self.eat_keyword(kw::Struct) { // STRUCT ITEM self.parse_item_struct()? } else if self.is_kw_followed_by_ident(kw::Union) { // UNION ITEM self.bump(); // `union` self.parse_item_union()? } else if self.eat_keyword(kw::Macro) { // MACROS 2.0 ITEM self.parse_item_decl_macro(lo)? } else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() { // MACRO_RULES ITEM self.parse_item_macro_rules(vis, has_bang)? } else if self.isnt_macro_invocation() && (self.token.is_ident_named(sym::import) || self.token.is_ident_named(sym::using) || self.token.is_ident_named(sym::include) || self.token.is_ident_named(sym::require)) { return self.recover_import_as_use(); } else if self.isnt_macro_invocation() && vis.kind.is_pub() { self.recover_missing_kw_before_item()?; return Ok(None); } else if self.isnt_macro_invocation() && case == Case::Sensitive { _ = def_; // Recover wrong cased keywords return self.parse_item_kind( attrs, macros_allowed, lo, vis, def, fn_parse_mode, Case::Insensitive, ); } else if macros_allowed && self.check_path() { // MACRO INVOCATION ITEM (Ident::empty(), ItemKind::MacCall(P(self.parse_item_macro(vis)?))) } else { return Ok(None); }; Ok(Some(info)) } fn recover_import_as_use(&mut self) -> PResult<'a, Option<(Ident, ItemKind)>> { let span = self.token.span; let token_name = super::token_descr(&self.token); let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); match self.parse_use_item() { Ok(u) => { self.struct_span_err(span, format!("expected item, found {token_name}")) .span_suggestion_short( span, "items are imported using the `use` keyword", "use", Applicability::MachineApplicable, ) .emit(); Ok(Some(u)) } Err(e) => { e.cancel(); self.restore_snapshot(snapshot); Ok(None) } } } fn parse_use_item(&mut self) -> PResult<'a, (Ident, ItemKind)> { let tree = self.parse_use_tree()?; if let Err(mut e) = self.expect_semi() { match tree.kind { UseTreeKind::Glob => { e.note("the wildcard token must be last on the path"); } UseTreeKind::Nested(..) => { e.note("glob-like brace syntax must be last on the path"); } _ => (), } return Err(e); } Ok((Ident::empty(), ItemKind::Use(tree))) } /// When parsing a statement, would the start of a path be an item? pub(super) fn is_path_start_item(&mut self) -> bool { self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }` || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }` || self.is_async_fn() // no(2015): `async::b`, yes: `async fn` || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac` } /// Are we sure this could not possibly be a macro invocation? fn isnt_macro_invocation(&mut self) -> bool { self.check_ident() && self.look_ahead(1, |t| *t != token::Not && *t != token::ModSep) } /// Recover on encountering a struct or method definition where the user /// forgot to add the `struct` or `fn` keyword after writing `pub`: `pub S {}`. fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> { // Space between `pub` keyword and the identifier // // pub S {} // ^^^ `sp` points here let sp = self.prev_token.span.between(self.token.span); let full_sp = self.prev_token.span.to(self.token.span); let ident_sp = self.token.span; if self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace)) { // possible public struct definition where `struct` was forgotten let ident = self.parse_ident().unwrap(); let msg = format!("add `struct` here to parse `{ident}` as a public struct"); let mut err = self.struct_span_err(sp, "missing `struct` for struct definition"); err.span_suggestion_short( sp, &msg, " struct ", Applicability::MaybeIncorrect, // speculative ); Err(err) } else if self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis)) { let ident = self.parse_ident().unwrap(); self.bump(); // `(` let kw_name = self.recover_first_param(); self.consume_block(Delimiter::Parenthesis, ConsumeClosingDelim::Yes); let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) { self.eat_to_tokens(&[&token::OpenDelim(Delimiter::Brace)]); self.bump(); // `{` ("fn", kw_name, false) } else if self.check(&token::OpenDelim(Delimiter::Brace)) { self.bump(); // `{` ("fn", kw_name, false) } else if self.check(&token::Colon) { let kw = "struct"; (kw, kw, false) } else { ("fn` or `struct", "function or struct", true) }; let msg = format!("missing `{kw}` for {kw_name} definition"); let mut err = self.struct_span_err(sp, &msg); if !ambiguous { self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes); let suggestion = format!("add `{kw}` here to parse `{ident}` as a public {kw_name}"); err.span_suggestion_short( sp, &suggestion, format!(" {kw} "), Applicability::MachineApplicable, ); } else if let Ok(snippet) = self.span_to_snippet(ident_sp) { err.span_suggestion( full_sp, "if you meant to call a macro, try", format!("{}!", snippet), // this is the `ambiguous` conditional branch Applicability::MaybeIncorrect, ); } else { err.help( "if you meant to call a macro, remove the `pub` \ and add a trailing `!` after the identifier", ); } Err(err) } else if self.look_ahead(1, |t| *t == token::Lt) { let ident = self.parse_ident().unwrap(); self.eat_to_tokens(&[&token::Gt]); self.bump(); // `>` let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(Delimiter::Parenthesis)) { ("fn", self.recover_first_param(), false) } else if self.check(&token::OpenDelim(Delimiter::Brace)) { ("struct", "struct", false) } else { ("fn` or `struct", "function or struct", true) }; let msg = format!("missing `{kw}` for {kw_name} definition"); let mut err = self.struct_span_err(sp, &msg); if !ambiguous { err.span_suggestion_short( sp, &format!("add `{kw}` here to parse `{ident}` as a public {kw_name}"), format!(" {} ", kw), Applicability::MachineApplicable, ); } Err(err) } else { Ok(()) } } /// Parses an item macro, e.g., `item!();`. fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> { let path = self.parse_path(PathStyle::Mod)?; // `foo::bar` self.expect(&token::Not)?; // `!` match self.parse_delim_args() { // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`. Ok(args) => { self.eat_semi_for_macro_if_needed(&args); self.complain_if_pub_macro(vis, false); Ok(MacCall { path, args, prior_type_ascription: self.last_type_ascription }) } Err(mut err) => { // Maybe the user misspelled `macro_rules` (issue #91227) if self.token.is_ident() && path.segments.len() == 1 && lev_distance("macro_rules", &path.segments[0].ident.to_string(), 3).is_some() { err.span_suggestion( path.span, "perhaps you meant to define a macro", "macro_rules", Applicability::MachineApplicable, ); } Err(err) } } } /// Recover if we parsed attributes and expected an item but there was none. fn recover_attrs_no_item(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> { let ([start @ end] | [start, .., end]) = attrs else { return Ok(()); }; let msg = if end.is_doc_comment() { "expected item after doc comment" } else { "expected item after attributes" }; let mut err = self.struct_span_err(end.span, msg); if end.is_doc_comment() { err.span_label(end.span, "this doc comment doesn't document anything"); } if end.meta_kind().is_some() { if self.token.kind == TokenKind::Semi { err.span_suggestion_verbose( self.token.span, "consider removing this semicolon", "", Applicability::MaybeIncorrect, ); } } if let [.., penultimate, _] = attrs { err.span_label(start.span.to(penultimate.span), "other attributes here"); } Err(err) } fn is_async_fn(&self) -> bool { self.token.is_keyword(kw::Async) && self.is_keyword_ahead(1, &[kw::Fn]) } fn parse_polarity(&mut self) -> ast::ImplPolarity { // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type. if self.check(&token::Not) && self.look_ahead(1, |t| t.can_begin_type()) { self.bump(); // `!` ast::ImplPolarity::Negative(self.prev_token.span) } else { ast::ImplPolarity::Positive } } /// Parses an implementation item. /// /// ```ignore (illustrative) /// impl<'a, T> TYPE { /* impl items */ } /// impl<'a, T> TRAIT for TYPE { /* impl items */ } /// impl<'a, T> !TRAIT for TYPE { /* impl items */ } /// impl<'a, T> const TRAIT for TYPE { /* impl items */ } /// ``` /// /// We actually parse slightly more relaxed grammar for better error reporting and recovery. /// ```ebnf /// "impl" GENERICS "const"? "!"? TYPE "for"? (TYPE | "..") ("where" PREDICATES)? "{" BODY "}" /// "impl" GENERICS "const"? "!"? TYPE ("where" PREDICATES)? "{" BODY "}" /// ``` fn parse_item_impl( &mut self, attrs: &mut AttrVec, defaultness: Defaultness, ) -> PResult<'a, ItemInfo> { let unsafety = self.parse_unsafety(Case::Sensitive); self.expect_keyword(kw::Impl)?; // First, parse generic parameters if necessary. let mut generics = if self.choose_generics_over_qpath(0) { self.parse_generics()? } else { let mut generics = Generics::default(); // impl A for B {} // /\ this is where `generics.span` should point when there are no type params. generics.span = self.prev_token.span.shrink_to_hi(); generics }; let constness = self.parse_constness(Case::Sensitive); if let Const::Yes(span) = constness { self.sess.gated_spans.gate(sym::const_trait_impl, span); } let polarity = self.parse_polarity(); // Parse both types and traits as a type, then reinterpret if necessary. let err_path = |span| ast::Path::from_ident(Ident::new(kw::Empty, span)); let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt) { let span = self.prev_token.span.between(self.token.span); self.struct_span_err(span, "missing trait in a trait impl") .span_suggestion( span, "add a trait here", " Trait ", Applicability::HasPlaceholders, ) .span_suggestion( span.to(self.token.span), "for an inherent impl, drop this `for`", "", Applicability::MaybeIncorrect, ) .emit(); P(Ty { kind: TyKind::Path(None, err_path(span)), span, id: DUMMY_NODE_ID, tokens: None, }) } else { self.parse_ty_with_generics_recovery(&generics)? }; // If `for` is missing we try to recover. let has_for = self.eat_keyword(kw::For); let missing_for_span = self.prev_token.span.between(self.token.span); let ty_second = if self.token == token::DotDot { // We need to report this error after `cfg` expansion for compatibility reasons self.bump(); // `..`, do not add it to expected tokens Some(self.mk_ty(self.prev_token.span, TyKind::Err)) } else if has_for || self.token.can_begin_type() { Some(self.parse_ty()?) } else { None }; generics.where_clause = self.parse_where_clause()?; let impl_items = self.parse_item_list(attrs, |p| p.parse_impl_item(ForceCollect::No))?; let item_kind = match ty_second { Some(ty_second) => { // impl Trait for Type if !has_for { self.struct_span_err(missing_for_span, "missing `for` in a trait impl") .span_suggestion_short( missing_for_span, "add `for` here", " for ", Applicability::MachineApplicable, ) .emit(); } let ty_first = ty_first.into_inner(); let path = match ty_first.kind { // This notably includes paths passed through `ty` macro fragments (#46438). TyKind::Path(None, path) => path, _ => { self.struct_span_err(ty_first.span, "expected a trait, found type").emit(); err_path(ty_first.span) } }; let trait_ref = TraitRef { path, ref_id: ty_first.id }; ItemKind::Impl(Box::new(Impl { unsafety, polarity, defaultness, constness, generics, of_trait: Some(trait_ref), self_ty: ty_second, items: impl_items, })) } None => { // impl Type ItemKind::Impl(Box::new(Impl { unsafety, polarity, defaultness, constness, generics, of_trait: None, self_ty: ty_first, items: impl_items, })) } }; Ok((Ident::empty(), item_kind)) } fn parse_item_list( &mut self, attrs: &mut AttrVec, mut parse_item: impl FnMut(&mut Parser<'a>) -> PResult<'a, Option>>, ) -> PResult<'a, Vec> { let open_brace_span = self.token.span; // Recover `impl Ty;` instead of `impl Ty {}` if self.token == TokenKind::Semi { self.sess.emit_err(UseEmptyBlockNotSemi { span: self.token.span }); self.bump(); return Ok(vec![]); } self.expect(&token::OpenDelim(Delimiter::Brace))?; attrs.extend(self.parse_inner_attributes()?); let mut items = Vec::new(); while !self.eat(&token::CloseDelim(Delimiter::Brace)) { if self.recover_doc_comment_before_brace() { continue; } self.recover_diff_marker(); match parse_item(self) { Ok(None) => { let mut is_unnecessary_semicolon = !items.is_empty() // When the close delim is `)` in a case like the following, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`, // but the actual `token.kind` is `token::CloseDelim(Delimiter::Brace)`. // This is because the `token.kind` of the close delim is treated as the same as // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different. // Therefore, `token.kind` should not be compared here. // // issue-60075.rs // ``` // trait T { // fn qux() -> Option { // let _ = if true { // }); // ^ this close delim // Some(4) // } // ``` && self .span_to_snippet(self.prev_token.span) .map_or(false, |snippet| snippet == "}") && self.token.kind == token::Semi; let mut semicolon_span = self.token.span; if !is_unnecessary_semicolon { // #105369, Detect spurious `;` before assoc fn body is_unnecessary_semicolon = self.token == token::OpenDelim(Delimiter::Brace) && self.prev_token.kind == token::Semi; semicolon_span = self.prev_token.span; } // We have to bail or we'll potentially never make progress. let non_item_span = self.token.span; let is_let = self.token.is_keyword(kw::Let); let mut err = self.struct_span_err(non_item_span, "non-item in item list"); self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes); if is_let { err.span_suggestion( non_item_span, "consider using `const` instead of `let` for associated const", "const", Applicability::MachineApplicable, ); } else { err.span_label(open_brace_span, "item list starts here") .span_label(non_item_span, "non-item starts here") .span_label(self.prev_token.span, "item list ends here"); } if is_unnecessary_semicolon { err.span_suggestion( semicolon_span, "consider removing this semicolon", "", Applicability::MaybeIncorrect, ); } err.emit(); break; } Ok(Some(item)) => items.extend(item), Err(mut err) => { self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes); err.span_label(open_brace_span, "while parsing this item list starting here") .span_label(self.prev_token.span, "the item list ends here") .emit(); break; } } } Ok(items) } /// Recover on a doc comment before `}`. fn recover_doc_comment_before_brace(&mut self) -> bool { if let token::DocComment(..) = self.token.kind { if self.look_ahead(1, |tok| tok == &token::CloseDelim(Delimiter::Brace)) { struct_span_err!( self.diagnostic(), self.token.span, E0584, "found a documentation comment that doesn't document anything", ) .span_label(self.token.span, "this doc comment doesn't document anything") .help( "doc comments must come before what they document, if a comment was \ intended use `//`", ) .emit(); self.bump(); return true; } } false } /// Parses defaultness (i.e., `default` or nothing). fn parse_defaultness(&mut self) -> Defaultness { // We are interested in `default` followed by another identifier. // However, we must avoid keywords that occur as binary operators. // Currently, the only applicable keyword is `as` (`default as Ty`). if self.check_keyword(kw::Default) && self.look_ahead(1, |t| t.is_non_raw_ident_where(|i| i.name != kw::As)) { self.bump(); // `default` Defaultness::Default(self.prev_token.uninterpolated_span()) } else { Defaultness::Final } } /// Is this an `(unsafe auto? | auto) trait` item? fn check_auto_or_unsafe_trait_item(&mut self) -> bool { // auto trait self.check_keyword(kw::Auto) && self.is_keyword_ahead(1, &[kw::Trait]) // unsafe auto trait || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) } /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemInfo> { let unsafety = self.parse_unsafety(Case::Sensitive); // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No }; self.expect_keyword(kw::Trait)?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; // Parse optional colon and supertrait bounds. let had_colon = self.eat(&token::Colon); let span_at_colon = self.prev_token.span; let bounds = if had_colon { self.parse_generic_bounds(Some(self.prev_token.span))? } else { Vec::new() }; let span_before_eq = self.prev_token.span; if self.eat(&token::Eq) { // It's a trait alias. if had_colon { let span = span_at_colon.to(span_before_eq); self.struct_span_err(span, "bounds are not allowed on trait aliases").emit(); } let bounds = self.parse_generic_bounds(None)?; generics.where_clause = self.parse_where_clause()?; self.expect_semi()?; let whole_span = lo.to(self.prev_token.span); if is_auto == IsAuto::Yes { let msg = "trait aliases cannot be `auto`"; self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit(); } if let Unsafe::Yes(_) = unsafety { let msg = "trait aliases cannot be `unsafe`"; self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit(); } self.sess.gated_spans.gate(sym::trait_alias, whole_span); Ok((ident, ItemKind::TraitAlias(generics, bounds))) } else { // It's a normal trait. generics.where_clause = self.parse_where_clause()?; let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?; Ok(( ident, ItemKind::Trait(Box::new(Trait { is_auto, unsafety, generics, bounds, items })), )) } } pub fn parse_impl_item( &mut self, force_collect: ForceCollect, ) -> PResult<'a, Option>>> { 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>>> { 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, fn_parse_mode: FnParseMode, force_collect: ForceCollect, ) -> PResult<'a, Option>>> { 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, Err(kind) => match kind { ItemKind::Static(a, _, b) => { self.struct_span_err(span, "associated `static` items are not allowed") .emit(); AssocItemKind::Const(Defaultness::Final, a, b) } _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"), }, }; Some(P(Item { attrs, id, span, vis, ident, kind, tokens })) }, )) } /// Parses a `type` alias with the following grammar: /// ```ebnf /// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ; /// ``` /// The `"type"` has already been eaten. fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemInfo> { let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; // Parse optional colon and param bounds. let bounds = if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() }; let before_where_clause = self.parse_where_clause()?; let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None }; let after_where_clause = self.parse_where_clause()?; let where_clauses = ( TyAliasWhereClause(before_where_clause.has_where_token, before_where_clause.span), TyAliasWhereClause(after_where_clause.has_where_token, after_where_clause.span), ); let where_predicates_split = before_where_clause.predicates.len(); let mut predicates = before_where_clause.predicates; predicates.extend(after_where_clause.predicates.into_iter()); let where_clause = WhereClause { has_where_token: before_where_clause.has_where_token || after_where_clause.has_where_token, predicates, span: DUMMY_SP, }; generics.where_clause = where_clause; self.expect_semi()?; Ok(( ident, ItemKind::TyAlias(Box::new(TyAlias { defaultness, generics, where_clauses, where_predicates_split, bounds, ty, })), )) } /// Parses a `UseTree`. /// /// ```text /// USE_TREE = [`::`] `*` | /// [`::`] `{` USE_TREE_LIST `}` | /// PATH `::` `*` | /// PATH `::` `{` USE_TREE_LIST `}` | /// PATH [`as` IDENT] /// ``` fn parse_use_tree(&mut self) -> PResult<'a, UseTree> { let lo = self.token.span; let mut prefix = ast::Path { segments: ThinVec::new(), span: lo.shrink_to_lo(), tokens: None }; let kind = if self.check(&token::OpenDelim(Delimiter::Brace)) || self.check(&token::BinOp(token::Star)) || self.is_import_coupler() { // `use *;` or `use ::*;` or `use {...};` or `use ::{...};` let mod_sep_ctxt = self.token.span.ctxt(); if self.eat(&token::ModSep) { prefix .segments .push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))); } self.parse_use_tree_glob_or_nested()? } else { // `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;` prefix = self.parse_path(PathStyle::Mod)?; if self.eat(&token::ModSep) { self.parse_use_tree_glob_or_nested()? } else { // Recover from using a colon as path separator. while self.eat_noexpect(&token::Colon) { self.struct_span_err(self.prev_token.span, "expected `::`, found `:`") .span_suggestion_short( self.prev_token.span, "use double colon", "::", Applicability::MachineApplicable, ) .note_once("import paths are delimited using `::`") .emit(); // We parse the rest of the path and append it to the original prefix. self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None)?; prefix.span = lo.to(self.prev_token.span); } UseTreeKind::Simple(self.parse_rename()?) } }; Ok(UseTree { prefix, kind, span: lo.to(self.prev_token.span) }) } /// Parses `*` or `{...}`. fn parse_use_tree_glob_or_nested(&mut self) -> PResult<'a, UseTreeKind> { Ok(if self.eat(&token::BinOp(token::Star)) { UseTreeKind::Glob } else { UseTreeKind::Nested(self.parse_use_tree_list()?) }) } /// Parses a `UseTreeKind::Nested(list)`. /// /// ```text /// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`] /// ``` fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> { self.parse_delim_comma_seq(Delimiter::Brace, |p| { p.recover_diff_marker(); Ok((p.parse_use_tree()?, DUMMY_NODE_ID)) }) .map(|(r, _)| r) } fn parse_rename(&mut self) -> PResult<'a, Option> { if self.eat_keyword(kw::As) { self.parse_ident_or_underscore().map(Some) } else { Ok(None) } } fn parse_ident_or_underscore(&mut self) -> PResult<'a, Ident> { match self.token.ident() { Some((ident @ Ident { name: kw::Underscore, .. }, false)) => { self.bump(); Ok(ident) } _ => self.parse_ident(), } } /// Parses `extern crate` links. /// /// # Examples /// /// ```ignore (illustrative) /// extern crate foo; /// extern crate bar as foo; /// ``` fn parse_item_extern_crate(&mut self) -> PResult<'a, ItemInfo> { // Accept `extern crate name-like-this` for better diagnostics let orig_name = self.parse_crate_name_with_dashes()?; let (item_name, orig_name) = if let Some(rename) = self.parse_rename()? { (rename, Some(orig_name.name)) } else { (orig_name, None) }; self.expect_semi()?; Ok((item_name, ItemKind::ExternCrate(orig_name))) } fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, Ident> { let error_msg = "crate name using dashes are not valid in `extern crate` statements"; let suggestion_msg = "if the original crate name uses dashes you need to use underscores \ in the code"; let mut ident = if self.token.is_keyword(kw::SelfLower) { self.parse_path_segment_ident() } else { self.parse_ident() }?; let mut idents = vec![]; let mut replacement = vec![]; let mut fixed_crate_name = false; // Accept `extern crate name-like-this` for better diagnostics. let dash = token::BinOp(token::BinOpToken::Minus); if self.token == dash { // Do not include `-` as part of the expected tokens list. while self.eat(&dash) { fixed_crate_name = true; replacement.push((self.prev_token.span, "_".to_string())); idents.push(self.parse_ident()?); } } if fixed_crate_name { let fixed_name_sp = ident.span.to(idents.last().unwrap().span); let mut fixed_name = ident.name.to_string(); for part in idents { fixed_name.push_str(&format!("_{}", part.name)); } ident = Ident::from_str_and_span(&fixed_name, fixed_name_sp); self.struct_span_err(fixed_name_sp, error_msg) .span_label(fixed_name_sp, "dash-separated idents are not valid") .multipart_suggestion(suggestion_msg, replacement, Applicability::MachineApplicable) .emit(); } Ok(ident) } /// Parses `extern` for foreign ABIs modules. /// /// `extern` is expected to have been consumed before calling this method. /// /// # Examples /// /// ```ignore (only-for-syntax-highlight) /// extern "C" {} /// extern {} /// ``` fn parse_item_foreign_mod( &mut self, attrs: &mut AttrVec, mut unsafety: Unsafe, ) -> PResult<'a, ItemInfo> { let abi = self.parse_abi(); // ABI? if unsafety == Unsafe::No && self.token.is_keyword(kw::Unsafe) && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Brace)) { let mut err = self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err(); err.emit(); unsafety = Unsafe::Yes(self.token.span); self.eat_keyword(kw::Unsafe); } let module = ast::ForeignMod { unsafety, abi, items: self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?, }; Ok((Ident::empty(), ItemKind::ForeignMod(module))) } /// Parses a foreign item (one in an `extern { ... }` block). pub fn parse_foreign_item( &mut self, force_collect: ForceCollect, ) -> PResult<'a, Option>>> { 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, Err(kind) => match kind { ItemKind::Const(_, a, b) => { self.error_on_foreign_const(span, ident); ForeignItemKind::Static(a, Mutability::Not, b) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), }, }; Some(P(Item { attrs, id, span, vis, ident, kind, tokens })) }, )) } fn error_bad_item_kind(&self, span: Span, kind: &ItemKind, ctx: &str) -> Option { let span = self.sess.source_map().guess_head_span(span); let descr = kind.descr(); self.struct_span_err(span, &format!("{descr} is not supported in {ctx}")) .help(&format!("consider moving the {descr} out to a nearby module scope")) .emit(); None } fn error_on_foreign_const(&self, span: Span, ident: Ident) { self.struct_span_err(ident.span, "extern items cannot be `const`") .span_suggestion( span.with_hi(ident.span.lo()), "try using a static value", "static ", Applicability::MachineApplicable, ) .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html") .emit(); } fn is_unsafe_foreign_mod(&self) -> bool { self.token.is_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Extern]) && self.look_ahead( 2 + self.look_ahead(2, |t| t.can_begin_literal_maybe_minus() as usize), |t| t.kind == token::OpenDelim(Delimiter::Brace), ) } fn is_static_global(&mut self) -> bool { if self.check_keyword(kw::Static) { // Check if this could be a closure. !self.look_ahead(1, |token| { if token.is_keyword(kw::Move) { return true; } matches!(token.kind, token::BinOp(token::Or) | token::OrOr) }) } else { false } } /// Recover on `const mut` with `const` already eaten. fn recover_const_mut(&mut self, const_span: Span) { if self.eat_keyword(kw::Mut) { let span = self.prev_token.span; self.struct_span_err(span, "const globals cannot be mutable") .span_label(span, "cannot be mutable") .span_suggestion( const_span, "you might want to declare a static instead", "static", Applicability::MaybeIncorrect, ) .emit(); } else if self.eat_keyword(kw::Let) { let span = self.prev_token.span; self.struct_span_err(const_span.to(span), "`const` and `let` are mutually exclusive") .span_suggestion( const_span.to(span), "remove `let`", "const", Applicability::MaybeIncorrect, ) .emit(); } } /// Recover on `const impl` with `const` already eaten. fn recover_const_impl( &mut self, const_span: Span, attrs: &mut AttrVec, defaultness: Defaultness, ) -> PResult<'a, ItemInfo> { let impl_span = self.token.span; let mut err = self.expected_ident_found(); // Only try to recover if this is implementing a trait for a type let mut impl_info = match self.parse_item_impl(attrs, defaultness) { Ok(impl_info) => impl_info, Err(recovery_error) => { // Recovery failed, raise the "expected identifier" error recovery_error.cancel(); return Err(err); } }; match &mut impl_info.1 { ItemKind::Impl(box Impl { of_trait: Some(trai), constness, .. }) => { *constness = Const::Yes(const_span); let before_trait = trai.path.span.shrink_to_lo(); let const_up_to_impl = const_span.with_hi(impl_span.lo()); err.multipart_suggestion( "you might have meant to write a const trait impl", vec![(const_up_to_impl, "".to_owned()), (before_trait, "const ".to_owned())], Applicability::MaybeIncorrect, ) .emit(); } ItemKind::Impl { .. } => return Err(err), _ => unreachable!(), } Ok(impl_info) } /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`. /// /// When `m` is `"const"`, `$ident` may also be `"_"`. fn parse_item_global( &mut self, m: Option, ) -> PResult<'a, (Ident, P, Option>)> { let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?; // Parse the type of a `const` or `static mut?` item. // That is, the `":" $ty` fragment. let ty = match (self.eat(&token::Colon), self.check(&token::Eq) | self.check(&token::Semi)) { // If there wasn't a `:` or the colon was followed by a `=` or `;` recover a missing type. (true, false) => self.parse_ty()?, (colon, _) => self.recover_missing_const_type(colon, m), }; let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None }; self.expect_semi()?; Ok((id, ty, expr)) } /// We were supposed to parse `":" $ty` but the `:` or the type was missing. /// This means that the type is missing. fn recover_missing_const_type(&mut self, colon_present: bool, m: Option) -> P { // Construct the error and stash it away with the hope // that typeck will later enrich the error with a type. let kind = match m { Some(Mutability::Mut) => "static mut", Some(Mutability::Not) => "static", None => "const", }; let colon = match colon_present { true => "", false => ":", }; let span = self.prev_token.span.shrink_to_hi(); let mut err = self.struct_span_err(span, &format!("missing type for `{kind}` item")); err.span_suggestion( span, "provide a type for the item", format!("{colon} "), Applicability::HasPlaceholders, ); err.stash(span, StashKey::ItemNoType); // The user intended that the type be inferred, // so treat this as if the user wrote e.g. `const A: _ = expr;`. P(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID, tokens: None }) } /// Parses an enum declaration. fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { if self.token.is_keyword(kw::Struct) { let span = self.prev_token.span.to(self.token.span); let mut err = self.struct_span_err(span, "`enum` and `struct` are mutually exclusive"); err.span_suggestion( span, "replace `enum struct` with", "enum", Applicability::MachineApplicable, ); if self.look_ahead(1, |t| t.is_ident()) { self.bump(); err.emit(); } else { return Err(err); } } let id = self.parse_ident()?; let mut generics = self.parse_generics()?; generics.where_clause = self.parse_where_clause()?; // Possibly recover `enum Foo;` instead of `enum Foo {}` let (variants, _) = if self.token == TokenKind::Semi { self.sess.emit_err(UseEmptyBlockNotSemi { span: self.token.span }); self.bump(); (vec![], false) } else { self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant()).map_err( |mut e| { e.span_label(id.span, "while parsing this enum"); self.recover_stmt(); e }, )? }; let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() }; Ok((id, ItemKind::Enum(enum_definition, generics))) } fn parse_enum_variant(&mut self) -> PResult<'a, Option> { self.recover_diff_marker(); let variant_attrs = self.parse_outer_attributes()?; self.recover_diff_marker(); self.collect_tokens_trailing_token( variant_attrs, ForceCollect::No, |this, variant_attrs| { let vlo = this.token.span; let vis = this.parse_visibility(FollowedByType::No)?; if !this.recover_nested_adt_item(kw::Enum)? { return Ok((None, TrailingToken::None)); } let ident = this.parse_field_ident("enum", vlo)?; let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) { // Parse a struct variant. let (fields, recovered) = this.parse_record_struct_body("struct", ident.span, false)?; VariantData::Struct(fields, recovered) } else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) { VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID) } else { VariantData::Unit(DUMMY_NODE_ID) }; let disr_expr = if this.eat(&token::Eq) { Some(this.parse_anon_const_expr()?) } else { None }; let vr = ast::Variant { ident, vis, id: DUMMY_NODE_ID, attrs: variant_attrs, data: struct_def, disr_expr, span: vlo.to(this.prev_token.span), is_placeholder: false, }; Ok((Some(vr), TrailingToken::MaybeComma)) }, ).map_err(|mut err|{ err.help("enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`"); err }) } /// Parses `struct Foo { ... }`. fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; let mut generics = self.parse_generics()?; // There is a special case worth noting here, as reported in issue #17904. // If we are parsing a tuple struct it is the case that the where clause // should follow the field list. Like so: // // struct Foo(T) where T: Copy; // // If we are parsing a normal record-style struct it is the case // that the where clause comes before the body, and after the generics. // So if we look ahead and see a brace or a where-clause we begin // parsing a record style struct. // // Otherwise if we look ahead and see a paren we parse a tuple-style // struct. let vdata = if self.token.is_keyword(kw::Where) { let tuple_struct_body; (generics.where_clause, tuple_struct_body) = self.parse_struct_where_clause(class_name, generics.span)?; if let Some(body) = tuple_struct_body { // If we see a misplaced tuple struct body: `struct Foo where T: Copy, (T);` let body = VariantData::Tuple(body, DUMMY_NODE_ID); self.expect_semi()?; body } else if self.eat(&token::Semi) { // If we see a: `struct Foo where T: Copy;` style decl. VariantData::Unit(DUMMY_NODE_ID) } else { // If we see: `struct Foo where T: Copy { ... }` let (fields, recovered) = self.parse_record_struct_body( "struct", class_name.span, generics.where_clause.has_where_token, )?; VariantData::Struct(fields, recovered) } // No `where` so: `struct Foo;` } else if self.eat(&token::Semi) { VariantData::Unit(DUMMY_NODE_ID) // Record-style struct definition } else if self.token == token::OpenDelim(Delimiter::Brace) { let (fields, recovered) = self.parse_record_struct_body( "struct", class_name.span, generics.where_clause.has_where_token, )?; VariantData::Struct(fields, recovered) // Tuple-style struct definition with optional where-clause. } else if self.token == token::OpenDelim(Delimiter::Parenthesis) { let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID); generics.where_clause = self.parse_where_clause()?; self.expect_semi()?; body } else { let token_str = super::token_descr(&self.token); let msg = &format!( "expected `where`, `{{`, `(`, or `;` after struct name, found {token_str}" ); let mut err = self.struct_span_err(self.token.span, msg); err.span_label(self.token.span, "expected `where`, `{`, `(`, or `;` after struct name"); return Err(err); }; Ok((class_name, ItemKind::Struct(vdata, generics))) } /// Parses `union Foo { ... }`. fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; let mut generics = self.parse_generics()?; let vdata = if self.token.is_keyword(kw::Where) { generics.where_clause = self.parse_where_clause()?; let (fields, recovered) = self.parse_record_struct_body( "union", class_name.span, generics.where_clause.has_where_token, )?; VariantData::Struct(fields, recovered) } else if self.token == token::OpenDelim(Delimiter::Brace) { let (fields, recovered) = self.parse_record_struct_body( "union", class_name.span, generics.where_clause.has_where_token, )?; VariantData::Struct(fields, recovered) } else { let token_str = super::token_descr(&self.token); let msg = &format!("expected `where` or `{{` after union name, found {token_str}"); let mut err = self.struct_span_err(self.token.span, msg); err.span_label(self.token.span, "expected `where` or `{` after union name"); return Err(err); }; Ok((class_name, ItemKind::Union(vdata, generics))) } fn parse_record_struct_body( &mut self, adt_ty: &str, ident_span: Span, parsed_where: bool, ) -> PResult<'a, (Vec, /* recovered */ bool)> { let mut fields = Vec::new(); let mut recovered = false; if self.eat(&token::OpenDelim(Delimiter::Brace)) { while self.token != token::CloseDelim(Delimiter::Brace) { let field = self.parse_field_def(adt_ty).map_err(|e| { self.consume_block(Delimiter::Brace, ConsumeClosingDelim::No); recovered = true; e }); match field { Ok(field) => fields.push(field), Err(mut err) => { err.span_label(ident_span, format!("while parsing this {adt_ty}")); err.emit(); break; } } } self.eat(&token::CloseDelim(Delimiter::Brace)); } else { let token_str = super::token_descr(&self.token); let msg = &format!( "expected {}`{{` after struct name, found {}", if parsed_where { "" } else { "`where`, or " }, token_str ); let mut err = self.struct_span_err(self.token.span, msg); err.span_label( self.token.span, format!( "expected {}`{{` after struct name", if parsed_where { "" } else { "`where`, or " } ), ); return Err(err); } Ok((fields, recovered)) } pub(super) fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec> { // This is the case where we find `struct Foo(T) where T: Copy;` // Unit like structs are handled in parse_item_struct function self.parse_paren_comma_seq(|p| { let attrs = p.parse_outer_attributes()?; p.collect_tokens_trailing_token(attrs, ForceCollect::No, |p, attrs| { let mut snapshot = None; if p.is_diff_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) { // Account for `<<<<<<<` diff markers. We can't proactively error here because // that can be a valid type start, so we snapshot and reparse only we've // encountered another parse error. snapshot = Some(p.create_snapshot_for_diagnostic()); } let lo = p.token.span; let vis = match p.parse_visibility(FollowedByType::Yes) { Ok(vis) => vis, Err(err) => { if let Some(ref mut snapshot) = snapshot { snapshot.recover_diff_marker(); } return Err(err); } }; let ty = match p.parse_ty() { Ok(ty) => ty, Err(err) => { if let Some(ref mut snapshot) = snapshot { snapshot.recover_diff_marker(); } return Err(err); } }; Ok(( FieldDef { span: lo.to(ty.span), vis, ident: None, id: DUMMY_NODE_ID, ty, attrs, is_placeholder: false, }, TrailingToken::MaybeComma, )) }) }) .map(|(r, _)| r) } /// Parses an element of a struct declaration. fn parse_field_def(&mut self, adt_ty: &str) -> PResult<'a, FieldDef> { self.recover_diff_marker(); let attrs = self.parse_outer_attributes()?; self.recover_diff_marker(); 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(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: AttrVec, ) -> PResult<'a, FieldDef> { let mut seen_comma: bool = false; let a_var = self.parse_name_and_ty(adt_ty, lo, vis, attrs)?; if self.token == token::Comma { seen_comma = true; } if self.eat(&token::Semi) { let sp = self.prev_token.span; let mut err = self.struct_span_err(sp, format!("{adt_ty} fields are separated by `,`")); err.span_suggestion_short( sp, "replace `;` with `,`", ",", Applicability::MachineApplicable, ); return Err(err); } match self.token.kind { token::Comma => { self.bump(); } token::CloseDelim(Delimiter::Brace) => {} token::DocComment(..) => { let previous_span = self.prev_token.span; let mut err = DocCommentDoesNotDocumentAnything { span: self.token.span, missing_comma: None, }; self.bump(); // consume the doc comment let comma_after_doc_seen = self.eat(&token::Comma); // `seen_comma` is always false, because we are inside doc block // condition is here to make code more readable if !seen_comma && comma_after_doc_seen { seen_comma = true; } if comma_after_doc_seen || self.token == token::CloseDelim(Delimiter::Brace) { self.sess.emit_err(err); } else { if !seen_comma { let sp = previous_span.shrink_to_hi(); err.missing_comma = Some(sp); } return Err(err.into_diagnostic(&self.sess.span_diagnostic)); } } _ => { let sp = self.prev_token.span.shrink_to_hi(); let mut err = self.struct_span_err( sp, &format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)), ); // Try to recover extra trailing angle brackets let mut recovered = false; if let TyKind::Path(_, Path { segments, .. }) = &a_var.ty.kind { if let Some(last_segment) = segments.last() { recovered = self.check_trailing_angle_brackets( last_segment, &[&token::Comma, &token::CloseDelim(Delimiter::Brace)], ); if recovered { // Handle a case like `Vec>,` where we can continue parsing fields // after the comma self.eat(&token::Comma); // `check_trailing_angle_brackets` already emitted a nicer error // NOTE(eddyb) this was `.cancel()`, but `err` // gets returned, so we can't fully defuse it. err.delay_as_bug(); } } } if self.token.is_ident() || (self.token.kind == TokenKind::Pound && (self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Bracket)))) { // This is likely another field, TokenKind::Pound is used for `#[..]` attribute for next field, // emit the diagnostic and keep going err.span_suggestion( sp, "try adding a comma", ",", Applicability::MachineApplicable, ); err.emit(); recovered = true; } if recovered { // Make sure an error was emitted (either by recovering an angle bracket, // or by finding an identifier as the next token), since we're // going to continue parsing assert!(self.sess.span_diagnostic.has_errors().is_some()); } else { return Err(err); } } } Ok(a_var) } fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> { if let Err(mut err) = self.expect(&token::Colon) { let sm = self.sess.source_map(); let eq_typo = self.token.kind == token::Eq && self.look_ahead(1, |t| t.is_path_start()); let semi_typo = self.token.kind == token::Semi && self.look_ahead(1, |t| { t.is_path_start() // We check that we are in a situation like `foo; bar` to avoid bad suggestions // when there's no type and `;` was used instead of a comma. && match (sm.lookup_line(self.token.span.hi()), sm.lookup_line(t.span.lo())) { (Ok(l), Ok(r)) => l.line == r.line, _ => true, } }); if eq_typo || semi_typo { self.bump(); // Gracefully handle small typos. err.span_suggestion_short( self.prev_token.span, "field names and their types are separated with `:`", ":", Applicability::MachineApplicable, ); err.emit(); } else { return Err(err); } } Ok(()) } /// Parses a structure field. fn parse_name_and_ty( &mut self, adt_ty: &str, lo: Span, vis: Visibility, attrs: AttrVec, ) -> PResult<'a, FieldDef> { let name = self.parse_field_ident(adt_ty, lo)?; self.expect_field_ty_separator()?; let ty = self.parse_ty()?; if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) { self.struct_span_err(self.token.span, "found single colon in a struct field type path") .span_suggestion_verbose( self.token.span, "write a path separator here", "::", Applicability::MaybeIncorrect, ) .emit(); } if self.token.kind == token::Eq { self.bump(); let const_expr = self.parse_anon_const_expr()?; let sp = ty.span.shrink_to_hi().to(const_expr.value.span); self.struct_span_err(sp, "default values on `struct` fields aren't supported") .span_suggestion( sp, "remove this unsupported default value", "", Applicability::MachineApplicable, ) .emit(); } Ok(FieldDef { span: lo.to(self.prev_token.span), ident: Some(name), vis, id: DUMMY_NODE_ID, ty, attrs, is_placeholder: false, }) } /// 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 snapshot = self.create_snapshot_for_diagnostic(); let err = if self.check_fn_front_matter(false, Case::Sensitive) { let inherited_vis = Visibility { span: rustc_span::DUMMY_SP, kind: VisibilityKind::Inherited, tokens: None, }; // We use `parse_fn` to get a span for the function let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true }; match self.parse_fn( &mut AttrVec::new(), fn_parse_mode, lo, &inherited_vis, Case::Insensitive, ) { Ok(_) => { let mut err = self.struct_span_err( lo.to(self.prev_token.span), &format!("functions are not allowed in {adt_ty} definitions"), ); 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 } Err(err) => { err.cancel(); self.restore_snapshot(snapshot); self.expected_ident_found() } } } else if self.eat_keyword(kw::Struct) { match self.parse_item_struct() { Ok((ident, _)) => { let mut err = self.struct_span_err( lo.with_hi(ident.span.hi()), &format!("structs are not allowed in {adt_ty} definitions"), ); err.help("consider creating a new `struct` definition instead of nesting"); err } Err(err) => { err.cancel(); self.restore_snapshot(snapshot); self.expected_ident_found() } } } else { let mut err = self.expected_ident_found(); if self.eat_keyword_noexpect(kw::Let) && let removal_span = self.prev_token.span.until(self.token.span) && let Ok(ident) = self.parse_ident_common(false) // Cancel this error, we don't need it. .map_err(|err| err.cancel()) && self.token.kind == TokenKind::Colon { err.span_suggestion( removal_span, "remove this `let` keyword", String::new(), Applicability::MachineApplicable, ); err.note("the `let` keyword is not allowed in `struct` fields"); err.note("see for more information"); err.emit(); return Ok(ident); } else { self.restore_snapshot(snapshot); } err }; return Err(err); } self.bump(); Ok(ident) } /// Parses a declarative macro 2.0 definition. /// The `macro` keyword has already been parsed. /// ```ebnf /// MacBody = "{" TOKEN_STREAM "}" ; /// MacParams = "(" TOKEN_STREAM ")" ; /// DeclMac = "macro" Ident MacParams? MacBody ; /// ``` fn parse_item_decl_macro(&mut self, lo: Span) -> PResult<'a, ItemInfo> { let ident = self.parse_ident()?; let body = if self.check(&token::OpenDelim(Delimiter::Brace)) { self.parse_delim_args()? // `MacBody` } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { let params = self.parse_token_tree(); // `MacParams` let pspan = params.span(); if !self.check(&token::OpenDelim(Delimiter::Brace)) { return self.unexpected(); } let body = self.parse_token_tree(); // `MacBody` // Convert `MacParams MacBody` into `{ MacParams => MacBody }`. let bspan = body.span(); let arrow = TokenTree::token_alone(token::FatArrow, pspan.between(bspan)); // `=>` let tokens = TokenStream::new(vec![params, arrow, body]); let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi()); P(DelimArgs { dspan, delim: MacDelimiter::Brace, tokens }) } else { return self.unexpected(); }; self.sess.gated_spans.gate(sym::decl_macro, lo.to(self.prev_token.span)); Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, macro_rules: false }))) } /// Is this a possibly malformed start of a `macro_rules! foo` item definition? fn is_macro_rules_item(&mut self) -> IsMacroRulesItem { if self.check_keyword(kw::MacroRules) { let macro_rules_span = self.token.span; if self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) { return IsMacroRulesItem::Yes { has_bang: true }; } else if self.look_ahead(1, |t| (t.is_ident())) { // macro_rules foo self.struct_span_err(macro_rules_span, "expected `!` after `macro_rules`") .span_suggestion( macro_rules_span, "add a `!`", "macro_rules!", Applicability::MachineApplicable, ) .emit(); return IsMacroRulesItem::Yes { has_bang: false }; } } IsMacroRulesItem::No } /// Parses a `macro_rules! foo { ... }` declarative macro. fn parse_item_macro_rules( &mut self, vis: &Visibility, has_bang: bool, ) -> PResult<'a, ItemInfo> { self.expect_keyword(kw::MacroRules)?; // `macro_rules` if has_bang { self.expect(&token::Not)?; // `!` } let ident = self.parse_ident()?; if self.eat(&token::Not) { // Handle macro_rules! foo! let span = self.prev_token.span; self.struct_span_err(span, "macro names aren't followed by a `!`") .span_suggestion(span, "remove the `!`", "", Applicability::MachineApplicable) .emit(); } let body = self.parse_delim_args()?; self.eat_semi_for_macro_if_needed(&body); self.complain_if_pub_macro(vis, true); Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, macro_rules: true }))) } /// Item macro invocations or `macro_rules!` definitions need inherited visibility. /// If that's not the case, emit an error. fn complain_if_pub_macro(&self, vis: &Visibility, macro_rules: bool) { if let VisibilityKind::Inherited = vis.kind { return; } let vstr = pprust::vis_to_string(vis); let vstr = vstr.trim_end(); if macro_rules { let msg = format!("can't qualify macro_rules invocation with `{vstr}`"); self.struct_span_err(vis.span, &msg) .span_suggestion( vis.span, "try exporting the macro", "#[macro_export]", Applicability::MaybeIncorrect, // speculative ) .emit(); } else { self.struct_span_err(vis.span, "can't qualify macro invocation with `pub`") .span_suggestion( vis.span, "remove the visibility", "", Applicability::MachineApplicable, ) .help(&format!("try adjusting the macro to put `{vstr}` inside the invocation")) .emit(); } } fn eat_semi_for_macro_if_needed(&mut self, args: &DelimArgs) { if args.need_semicolon() && !self.eat(&token::Semi) { self.report_invalid_macro_expansion_item(args); } } fn report_invalid_macro_expansion_item(&self, args: &DelimArgs) { let span = args.dspan.entire(); let mut err = self.struct_span_err( span, "macros that expand to items must be delimited with braces or followed by a semicolon", ); // FIXME: This will make us not emit the help even for declarative // macros within the same crate (that we can fix), which is sad. if !span.from_expansion() { if self.unclosed_delims.is_empty() { let DelimSpan { open, close } = args.dspan; err.multipart_suggestion( "change the delimiters to curly braces", vec![(open, "{".to_string()), (close, '}'.to_string())], Applicability::MaybeIncorrect, ); } else { err.span_suggestion( span, "change the delimiters to curly braces", " { /* items */ }", Applicability::HasPlaceholders, ); } err.span_suggestion( span.shrink_to_hi(), "add a semicolon", ';', Applicability::MaybeIncorrect, ); } err.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)) && self.look_ahead(1, |t| t.is_ident()) { let kw_token = self.token.clone(); let kw_str = pprust::token_to_string(&kw_token); let item = self.parse_item(ForceCollect::No)?; self.struct_span_err( kw_token.span, &format!("`{kw_str}` definition cannot be nested inside `{keyword}`"), ) .span_suggestion( item.unwrap().span, &format!("consider creating a new `{kw_str}` definition instead of nesting"), "", Applicability::MaybeIncorrect, ) .emit(); // We successfully parsed the item but we must inform the caller about nested problem. return Ok(false); } Ok(true) } } /// 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 AttrVec, fn_parse_mode: FnParseMode, sig_lo: Span, vis: &Visibility, case: Case, ) -> PResult<'a, (Ident, FnSig, Generics, Option>)> { let fn_span = self.token.span; let header = self.parse_fn_front_matter(vis, case)?; // `const ... fn` let ident = self.parse_ident()?; // `foo` let mut generics = self.parse_generics()?; // `<'a, T, ...>` let decl = match self.parse_fn_decl( fn_parse_mode.req_name, AllowPlus::Yes, RecoverReturnSign::Yes, ) { Ok(decl) => decl, Err(old_err) => { // If we see `for Ty ...` then user probably meant `impl` item. if self.token.is_keyword(kw::For) { old_err.cancel(); return Err(self.sess.create_err(FnTypoWithImpl { fn_span })); } else { return Err(old_err); } } }; 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, 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)) } /// Parse the "body" of a function. /// This can either be `;` when there's no body, /// or e.g. a block when the function is a provided one. fn parse_fn_body( &mut self, attrs: &mut AttrVec, ident: &Ident, sig_hi: &mut Span, req_body: bool, ) -> PResult<'a, Option>> { 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; (AttrVec::new(), None) } else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() { self.parse_block_common(self.token.span, BlockCheckMode::Default, false) .map(|(attrs, body)| (attrs, Some(body)))? } else if self.token.kind == token::Eq { // Recover `fn foo() = $expr;`. self.bump(); // `=` let eq_sp = self.prev_token.span; let _ = self.parse_expr()?; self.expect_semi()?; // `;` let span = eq_sp.to(self.prev_token.span); self.struct_span_err(span, "function body cannot be `= expression;`") .multipart_suggestion( "surround the expression with `{` and `}` instead of `=` and `;`", vec![(eq_sp, "{".to_string()), (self.prev_token.span, " }".to_string())], Applicability::MachineApplicable, ) .emit(); (AttrVec::new(), Some(self.mk_block_err(span))) } else { let expected = if req_body { &[token::OpenDelim(Delimiter::Brace)][..] } else { &[token::Semi, token::OpenDelim(Delimiter::Brace)] }; if let Err(mut err) = self.expected_one_of_not_found(&[], &expected) { if self.token.kind == token::CloseDelim(Delimiter::Brace) { // The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in // the AST for typechecking. err.span_label(ident.span, "while parsing this `fn`"); err.emit(); } else { return Err(err); } } (AttrVec::new(), None) }; attrs.extend(inner_attrs); Ok(body) } /// Is the current token the start of an `FnHeader` / not a valid parse? /// /// `check_pub` adds additional `pub` to the checks in case users place it /// wrongly, can be used to ensure `pub` never comes after `default`. pub(super) fn check_fn_front_matter(&mut self, check_pub: bool, case: Case) -> bool { // We use an over-approximation here. // `const const`, `fn const` won't parse, but we're not stepping over other syntax either. // `pub` is added in case users got confused with the ordering like `async pub fn`, // only if it wasn't preceded by `default` as `default pub` is invalid. let quals: &[Symbol] = if check_pub { &[kw::Pub, kw::Const, kw::Async, kw::Unsafe, kw::Extern] } else { &[kw::Const, kw::Async, kw::Unsafe, kw::Extern] }; self.check_keyword_case(kw::Fn, case) // Definitely an `fn`. // `$qual fn` or `$qual $qual`: || quals.iter().any(|&kw| self.check_keyword_case(kw, case)) && self.look_ahead(1, |t| { // `$qual fn`, e.g. `const fn` or `async fn`. t.is_keyword_case(kw::Fn, case) // Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`. || ( ( t.is_non_raw_ident_where(|i| quals.contains(&i.name) // Rule out 2015 `const async: T = val`. && i.is_reserved() ) || case == Case::Insensitive && t.is_non_raw_ident_where(|i| quals.iter().any(|qual| qual.as_str() == i.name.as_str().to_lowercase())) ) // Rule out unsafe extern block. && !self.is_unsafe_foreign_mod()) }) // `extern ABI fn` || self.check_keyword_case(kw::Extern, case) && self.look_ahead(1, |t| t.can_begin_literal_maybe_minus()) && self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case)) } /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration, /// up to and including the `fn` keyword. The formal grammar is: /// /// ```text /// Extern = "extern" StringLit? ; /// FnQual = "const"? "async"? "unsafe"? Extern? ; /// FnFrontMatter = FnQual "fn" ; /// ``` /// /// `vis` represents the visibility that was already parsed, if any. Use /// `Visibility::Inherited` when no visibility is known. pub(super) fn parse_fn_front_matter( &mut self, orig_vis: &Visibility, case: Case, ) -> PResult<'a, FnHeader> { let sp_start = self.token.span; let constness = self.parse_constness(case); let async_start_sp = self.token.span; let asyncness = self.parse_asyncness(case); let unsafe_start_sp = self.token.span; let unsafety = self.parse_unsafety(case); let ext_start_sp = self.token.span; let ext = self.parse_extern(case); if let Async::Yes { span, .. } = asyncness { self.ban_async_in_2015(span); } if !self.eat_keyword_case(kw::Fn, case) { // It is possible for `expect_one_of` to recover given the contents of // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't // account for this. match self.expect_one_of(&[], &[]) { Ok(true) => {} Ok(false) => unreachable!(), Err(mut err) => { // Qualifier keywords ordering check enum WrongKw { Duplicated(Span), Misplaced(Span), } // This will allow the machine fix to directly place the keyword in the correct place or to indicate // that the keyword is already present and the second instance should be removed. let wrong_kw = if self.check_keyword(kw::Const) { match constness { Const::Yes(sp) => Some(WrongKw::Duplicated(sp)), Const::No => Some(WrongKw::Misplaced(async_start_sp)), } } else if self.check_keyword(kw::Async) { match asyncness { Async::Yes { span, .. } => Some(WrongKw::Duplicated(span)), Async::No => Some(WrongKw::Misplaced(unsafe_start_sp)), } } else if self.check_keyword(kw::Unsafe) { match unsafety { Unsafe::Yes(sp) => Some(WrongKw::Duplicated(sp)), Unsafe::No => Some(WrongKw::Misplaced(ext_start_sp)), } } else { None }; // The keyword is already present, suggest removal of the second instance if let Some(WrongKw::Duplicated(original_sp)) = wrong_kw { let original_kw = self .span_to_snippet(original_sp) .expect("Span extracted directly from keyword should always work"); err.span_suggestion( self.token.uninterpolated_span(), &format!("`{original_kw}` already used earlier, remove this one"), "", Applicability::MachineApplicable, ) .span_note(original_sp, &format!("`{original_kw}` first seen here")); } // The keyword has not been seen yet, suggest correct placement in the function front matter else if let Some(WrongKw::Misplaced(correct_pos_sp)) = wrong_kw { let correct_pos_sp = correct_pos_sp.to(self.prev_token.span); if let Ok(current_qual) = self.span_to_snippet(correct_pos_sp) { let misplaced_qual_sp = self.token.uninterpolated_span(); let misplaced_qual = self.span_to_snippet(misplaced_qual_sp).unwrap(); err.span_suggestion( correct_pos_sp.to(misplaced_qual_sp), &format!("`{misplaced_qual}` must come before `{current_qual}`"), format!("{misplaced_qual} {current_qual}"), Applicability::MachineApplicable, ).note("keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`"); } } // Recover incorrect visibility order such as `async pub` else if self.check_keyword(kw::Pub) { let sp = sp_start.to(self.prev_token.span); if let Ok(snippet) = self.span_to_snippet(sp) { let current_vis = match self.parse_visibility(FollowedByType::No) { Ok(v) => v, Err(d) => { d.cancel(); return Err(err); } }; let vs = pprust::vis_to_string(¤t_vis); let vs = vs.trim_end(); // There was no explicit visibility if matches!(orig_vis.kind, VisibilityKind::Inherited) { err.span_suggestion( sp_start.to(self.prev_token.span), &format!("visibility `{vs}` must come before `{snippet}`"), format!("{vs} {snippet}"), Applicability::MachineApplicable, ); } // There was an explicit visibility else { err.span_suggestion( current_vis.span, "there is already a visibility modifier, remove one", "", Applicability::MachineApplicable, ) .span_note(orig_vis.span, "explicit visibility first seen here"); } } } return Err(err); } } } Ok(FnHeader { constness, unsafety, asyncness, ext }) } /// We are parsing `async fn`. If we are on Rust 2015, emit an error. fn ban_async_in_2015(&self, span: Span) { if span.rust_2015() { let diag = self.diagnostic(); struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015") .span_label(span, "to use `async fn`, switch to Rust 2018 or later") .help_use_latest_edition() .emit(); } } /// Parses the parameter list and result type of a function declaration. pub(super) fn parse_fn_decl( &mut self, req_name: ReqName, ret_allow_plus: AllowPlus, recover_return_sign: RecoverReturnSign, ) -> PResult<'a, P> { Ok(P(FnDecl { inputs: self.parse_fn_params(req_name)?, output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, recover_return_sign)?, })) } /// Parses the parameter list of a function, including the `(` and `)` delimiters. pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec> { let mut first_param = true; // Parse the arguments, starting out with `self` being allowed... let (mut params, _) = self.parse_paren_comma_seq(|p| { p.recover_diff_marker(); let param = p.parse_param_general(req_name, first_param).or_else(|mut e| { e.emit(); let lo = p.prev_token.span; // Skip every token until next possible arg or end. p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(Delimiter::Parenthesis)]); // Create a placeholder argument for proper arg count (issue #34264). Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span)))) }); // ...now that we've parsed the first argument, `self` is no longer allowed. first_param = false; param })?; // Replace duplicated recovered params with `_` pattern to avoid unnecessary errors. self.deduplicate_recovered_params_names(&mut params); Ok(params) } /// Parses a single function parameter. /// /// - `self` is syntactically allowed when `first_param` holds. fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResult<'a, Param> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here. if let Some(mut param) = this.parse_self_param()? { param.attrs = attrs; let res = if first_param { Ok(param) } else { this.recover_bad_self_param(param) }; return Ok((res?, TrailingToken::None)); } let is_name_required = match this.token.kind { token::DotDotDot => false, _ => req_name(this.token.span.edition()), }; let (pat, ty) = if is_name_required || this.is_named_param() { debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); let (pat, colon) = this.parse_fn_param_pat_colon()?; if !colon { let mut err = this.unexpected::<()>().unwrap_err(); return if let Some(ident) = this.parameter_without_type(&mut err, pat, is_name_required, first_param) { err.emit(); Ok((dummy_arg(ident), TrailingToken::None)) } else { Err(err) }; } this.eat_incorrect_doc_comment_for_param_type(); (pat, this.parse_ty_for_param()?) } else { debug!("parse_param_general ident_to_pat"); let parser_snapshot_before_ty = this.create_snapshot_for_diagnostic(); this.eat_incorrect_doc_comment_for_param_type(); let mut ty = this.parse_ty_for_param(); if ty.is_ok() && this.token != token::Comma && this.token != token::CloseDelim(Delimiter::Parenthesis) { // This wasn't actually a type, but a pattern looking like a type, // so we are going to rollback and re-parse for recovery. ty = this.unexpected(); } match ty { Ok(ty) => { let ident = Ident::new(kw::Empty, this.prev_token.span); let bm = BindingAnnotation::NONE; let pat = this.mk_pat_ident(ty.span, bm, ident); (pat, ty) } // If this is a C-variadic argument and we hit an error, return the error. Err(err) if this.token == token::DotDotDot => return Err(err), // Recover from attempting to parse the argument as a type without pattern. Err(err) => { err.cancel(); this.restore_snapshot(parser_snapshot_before_ty); this.recover_arg_parse()? } } }; let span = lo.to(this.prev_token.span); Ok(( Param { attrs, id: ast::DUMMY_NODE_ID, is_placeholder: false, pat, span, ty }, TrailingToken::None, )) }) } /// Returns the parsed optional self parameter and whether a self shortcut was used. fn parse_self_param(&mut self) -> PResult<'a, Option> { // Extract an identifier *after* having confirmed that the token is one. let expect_self_ident = |this: &mut Self| match this.token.ident() { Some((ident, false)) => { this.bump(); ident } _ => unreachable!(), }; // Is `self` `n` tokens ahead? let is_isolated_self = |this: &Self, n| { this.is_keyword_ahead(n, &[kw::SelfLower]) && this.look_ahead(n + 1, |t| t != &token::ModSep) }; // Is `mut self` `n` tokens ahead? let is_isolated_mut_self = |this: &Self, n| this.is_keyword_ahead(n, &[kw::Mut]) && is_isolated_self(this, n + 1); // Parse `self` or `self: TYPE`. We already know the current token is `self`. let parse_self_possibly_typed = |this: &mut Self, m| { let eself_ident = expect_self_ident(this); let eself_hi = this.prev_token.span; let eself = if this.eat(&token::Colon) { SelfKind::Explicit(this.parse_ty()?, m) } else { SelfKind::Value(m) }; Ok((eself, eself_ident, eself_hi)) }; // Recover for the grammar `*self`, `*const self`, and `*mut self`. let recover_self_ptr = |this: &mut Self| { let msg = "cannot pass `self` by raw pointer"; let span = this.token.span; this.struct_span_err(span, msg).span_label(span, msg).emit(); Ok((SelfKind::Value(Mutability::Not), expect_self_ident(this), this.prev_token.span)) }; // Parse optional `self` parameter of a method. // Only a limited set of initial token sequences is considered `self` parameters; anything // else is parsed as a normal function parameter list, so some lookahead is required. let eself_lo = self.token.span; let (eself, eself_ident, eself_hi) = match self.token.uninterpolate().kind { token::BinOp(token::And) => { let eself = if is_isolated_self(self, 1) { // `&self` self.bump(); SelfKind::Region(None, Mutability::Not) } else if is_isolated_mut_self(self, 1) { // `&mut self` self.bump(); self.bump(); SelfKind::Region(None, Mutability::Mut) } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) { // `&'lt self` self.bump(); let lt = self.expect_lifetime(); SelfKind::Region(Some(lt), Mutability::Not) } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_mut_self(self, 2) { // `&'lt mut self` self.bump(); let lt = self.expect_lifetime(); self.bump(); SelfKind::Region(Some(lt), Mutability::Mut) } else { // `¬_self` return Ok(None); }; (eself, expect_self_ident(self), self.prev_token.span) } // `*self` token::BinOp(token::Star) if is_isolated_self(self, 1) => { self.bump(); recover_self_ptr(self)? } // `*mut self` and `*const self` token::BinOp(token::Star) if self.look_ahead(1, |t| t.is_mutability()) && is_isolated_self(self, 2) => { self.bump(); self.bump(); recover_self_ptr(self)? } // `self` and `self: TYPE` token::Ident(..) if is_isolated_self(self, 0) => { parse_self_possibly_typed(self, Mutability::Not)? } // `mut self` and `mut self: TYPE` token::Ident(..) if is_isolated_mut_self(self, 0) => { self.bump(); parse_self_possibly_typed(self, Mutability::Mut)? } _ => return Ok(None), }; let eself = source_map::respan(eself_lo.to(eself_hi), eself); Ok(Some(Param::from_self(AttrVec::default(), eself, eself_ident))) } fn is_named_param(&self) -> bool { let offset = match &self.token.kind { token::Interpolated(nt) => match **nt { token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), _ => 0, }, token::BinOp(token::And) | token::AndAnd => 1, _ if self.token.is_keyword(kw::Mut) => 1, _ => 0, }; self.look_ahead(offset, |t| t.is_ident()) && self.look_ahead(offset + 1, |t| t == &token::Colon) } fn recover_first_param(&mut self) -> &'static str { match self .parse_outer_attributes() .and_then(|_| self.parse_self_param()) .map_err(|e| e.cancel()) { Ok(Some(_)) => "method", _ => "function", } } } enum IsMacroRulesItem { Yes { has_bang: bool }, No, }