1use std::fmt::Write;2use std::mem;34use ast::token::IdentIsRaw;5use rustc_ast as ast;6use rustc_ast::ast::*;7use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, TokenKind};8use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};9use rustc_ast::util::case::Case;10use rustc_ast_pretty::pprust;11use rustc_errors::codes::*;12use rustc_errors::{Applicability, PResult, StashKey, msg, struct_span_code_err};13use rustc_session::lint::builtin::VARARGS_WITHOUT_PATTERN;14use rustc_span::edit_distance::edit_distance;15use rustc_span::edition::Edition;16use rustc_span::{DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, respan, sym};17use thin_vec::{ThinVec, thin_vec};18use tracing::debug;1920use super::diagnostics::{ConsumeClosingDelim, dummy_arg};21use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};22use super::{23 AllowConstBlockItems, AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect,24 Parser, PathStyle, Recovered, Trailing, UsePreAttrPos,25};26use crate::errors::{self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField};27use crate::exp;2829impl<'a> Parser<'a> {30 /// Parses a source module as a crate. This is the main entry point for the parser.31 pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {32 let (attrs, items, spans) = self.parse_mod(exp!(Eof))?;33 Ok(ast::Crate { attrs, items, spans, id: DUMMY_NODE_ID, is_placeholder: false })34 }3536 /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.37 fn parse_item_mod(&mut self, attrs: &mut AttrVec) -> PResult<'a, ItemKind> {38 let safety = self.parse_safety(Case::Sensitive);39 self.expect_keyword(exp!(Mod))?;40 let ident = self.parse_ident()?;41 let mod_kind = if self.eat(exp!(Semi)) {42 ModKind::Unloaded43 } else {44 self.expect(exp!(OpenBrace))?;45 let (inner_attrs, items, inner_span) = self.parse_mod(exp!(CloseBrace))?;46 attrs.extend(inner_attrs);47 ModKind::Loaded(items, Inline::Yes, inner_span)48 };49 Ok(ItemKind::Mod(safety, ident, mod_kind))50 }5152 /// Parses the contents of a module (inner attributes followed by module items).53 /// We exit once we hit `term` which can be either54 /// - EOF (for files)55 /// - `}` for mod items56 pub fn parse_mod(57 &mut self,58 term: ExpTokenPair,59 ) -> PResult<'a, (AttrVec, ThinVec<Box<Item>>, ModSpans)> {60 let lo = self.token.span;61 let attrs = self.parse_inner_attributes()?;6263 let post_attr_lo = self.token.span;64 let mut items: ThinVec<Box<_>> = ThinVec::new();6566 // There shouldn't be any stray semicolons before or after items.67 // `parse_item` consumes the appropriate semicolons so any leftover is an error.68 loop {69 while self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {} // Eat all bad semicolons70 let Some(item) = self.parse_item(ForceCollect::No, AllowConstBlockItems::Yes)? else {71 break;72 };73 items.push(item);74 }7576 if !self.eat(term) {77 let token_str = super::token_descr(&self.token);78 if !self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {79 let is_let = self.token.is_keyword(kw::Let);80 let is_let_mut = is_let && self.look_ahead(1, |t| t.is_keyword(kw::Mut));81 let let_has_ident = is_let && !is_let_mut && self.is_kw_followed_by_ident(kw::Let);8283 let msg = format!("expected item, found {token_str}");84 let mut err = self.dcx().struct_span_err(self.token.span, msg);8586 let label = if is_let {87 "`let` cannot be used for global variables"88 } else {89 "expected item"90 };91 err.span_label(self.token.span, label);9293 if is_let {94 if is_let_mut {95 err.help("consider using `static` and a `Mutex` instead of `let mut`");96 } else if let_has_ident {97 err.span_suggestion_short(98 self.token.span,99 "consider using `static` or `const` instead of `let`",100 "static",101 Applicability::MaybeIncorrect,102 );103 } else {104 err.help("consider using `static` or `const` instead of `let`");105 }106 }107 err.note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>");108 return Err(err);109 }110 }111112 let inject_use_span = post_attr_lo.data().with_hi(post_attr_lo.lo());113 let mod_spans = ModSpans { inner_span: lo.to(self.prev_token.span), inject_use_span };114 Ok((attrs, items, mod_spans))115 }116}117118enum ReuseKind {119 Path,120 Impl,121}122123impl<'a> Parser<'a> {124 pub fn parse_item(125 &mut self,126 force_collect: ForceCollect,127 allow_const_block_items: AllowConstBlockItems,128 ) -> PResult<'a, Option<Box<Item>>> {129 let fn_parse_mode =130 FnParseMode { req_name: |_, _| true, context: FnContext::Free, req_body: true };131 self.parse_item_(fn_parse_mode, force_collect, allow_const_block_items)132 .map(|i| i.map(Box::new))133 }134135 fn parse_item_(136 &mut self,137 fn_parse_mode: FnParseMode,138 force_collect: ForceCollect,139 const_block_items_allowed: AllowConstBlockItems,140 ) -> PResult<'a, Option<Item>> {141 self.recover_vcs_conflict_marker();142 let attrs = self.parse_outer_attributes()?;143 self.recover_vcs_conflict_marker();144 self.parse_item_common(145 attrs,146 true,147 false,148 fn_parse_mode,149 force_collect,150 const_block_items_allowed,151 )152 }153154 pub(super) fn parse_item_common(155 &mut self,156 attrs: AttrWrapper,157 mac_allowed: bool,158 attrs_allowed: bool,159 fn_parse_mode: FnParseMode,160 force_collect: ForceCollect,161 allow_const_block_items: AllowConstBlockItems,162 ) -> PResult<'a, Option<Item>> {163 if let Some(item) = self.eat_metavar_seq(MetaVarKind::Item, |this| {164 this.parse_item(ForceCollect::Yes, allow_const_block_items)165 }) {166 let mut item = item.expect("an actual item");167 attrs.prepend_to_nt_inner(&mut item.attrs);168 return Ok(Some(*item));169 }170171 self.collect_tokens(None, attrs, force_collect, |this, mut attrs| {172 let lo = this.token.span;173 let vis = this.parse_visibility(FollowedByType::No)?;174 let mut def = this.parse_defaultness();175 let kind = this.parse_item_kind(176 &mut attrs,177 mac_allowed,178 allow_const_block_items,179 lo,180 &vis,181 &mut def,182 fn_parse_mode,183 Case::Sensitive,184 )?;185 if let Some(kind) = kind {186 this.error_on_unconsumed_default(def, &kind);187 let span = lo.to(this.prev_token.span);188 let id = DUMMY_NODE_ID;189 let item = Item { attrs, id, kind, vis, span, tokens: None };190 return Ok((Some(item), Trailing::No, UsePreAttrPos::No));191 }192193 // At this point, we have failed to parse an item.194 if !matches!(vis.kind, VisibilityKind::Inherited) {195 let vis_str = pprust::vis_to_string(&vis).trim_end().to_string();196 let mut err = this.dcx().create_err(errors::VisibilityNotFollowedByItem {197 span: vis.span,198 vis: vis_str,199 });200 if let Some((ident, _)) = this.token.ident()201 && !ident.is_used_keyword()202 && let Some((similar_kw, is_incorrect_case)) = ident203 .name204 .find_similar(&rustc_span::symbol::used_keywords(|| ident.span.edition()))205 {206 err.subdiagnostic(errors::MisspelledKw {207 similar_kw: similar_kw.to_string(),208 span: ident.span,209 is_incorrect_case,210 });211 }212 err.emit();213 }214215 if let Defaultness::Default(span) = def {216 this.dcx().emit_err(errors::DefaultNotFollowedByItem { span });217 } else if let Defaultness::Final(span) = def {218 this.dcx().emit_err(errors::FinalNotFollowedByItem { span });219 }220221 if !attrs_allowed {222 this.recover_attrs_no_item(&attrs)?;223 }224 Ok((None, Trailing::No, UsePreAttrPos::No))225 })226 }227228 /// Error in-case `default`/`final` was parsed in an in-appropriate context.229 fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {230 match def {231 Defaultness::Default(span) => {232 self.dcx().emit_err(errors::InappropriateDefault {233 span,234 article: kind.article(),235 descr: kind.descr(),236 });237 }238 Defaultness::Final(span) => {239 self.dcx().emit_err(errors::InappropriateFinal {240 span,241 article: kind.article(),242 descr: kind.descr(),243 });244 }245 Defaultness::Implicit => (),246 }247 }248249 /// Parses one of the items allowed by the flags.250 fn parse_item_kind(251 &mut self,252 attrs: &mut AttrVec,253 macros_allowed: bool,254 allow_const_block_items: AllowConstBlockItems,255 lo: Span,256 vis: &Visibility,257 def: &mut Defaultness,258 fn_parse_mode: FnParseMode,259 case: Case,260 ) -> PResult<'a, Option<ItemKind>> {261 let check_pub = def == &Defaultness::Implicit;262 let mut def_ = || mem::replace(def, Defaultness::Implicit);263264 let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) {265 self.parse_use_item()?266 } else if self.check_fn_front_matter(check_pub, case) {267 // FUNCTION ITEM268 let defaultness = def_();269 if let Defaultness::Default(span) = defaultness {270 // Default functions should only require feature `min_specialization`. We remove the271 // `specialization` tag again as such spans *require* feature `specialization` to be272 // enabled. In a later stage, we make `specialization` imply `min_specialization`.273 self.psess.gated_spans.gate(sym::min_specialization, span);274 self.psess.gated_spans.ungate_last(sym::specialization, span);275 }276 let (ident, sig, generics, contract, body) =277 self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?;278 ItemKind::Fn(Box::new(Fn {279 defaultness,280 ident,281 sig,282 generics,283 contract,284 body,285 define_opaque: None,286 eii_impls: ThinVec::new(),287 }))288 } else if self.eat_keyword_case(exp!(Extern), case) {289 if self.eat_keyword_case(exp!(Crate), case) {290 // EXTERN CRATE291 self.parse_item_extern_crate()?292 } else {293 // EXTERN BLOCK294 self.parse_item_foreign_mod(attrs, Safety::Default)?295 }296 } else if self.is_unsafe_foreign_mod() {297 // EXTERN BLOCK298 let safety = self.parse_safety(Case::Sensitive);299 self.expect_keyword(exp!(Extern))?;300 self.parse_item_foreign_mod(attrs, safety)?301 } else if let Some(safety) = self.parse_global_static_front_matter(case) {302 // STATIC ITEM303 let mutability = self.parse_mutability();304 self.parse_static_item(safety, mutability)?305 } else if self.check_keyword_case(exp!(Trait), case) || self.check_trait_front_matter() {306 // TRAIT ITEM307 self.parse_item_trait(attrs, lo)?308 } else if self.check_impl_frontmatter(0) {309 // IMPL ITEM310 self.parse_item_impl(attrs, def_(), false)?311 } else if let AllowConstBlockItems::Yes | AllowConstBlockItems::DoesNotMatter =312 allow_const_block_items313 && self.check_inline_const(0)314 {315 // CONST BLOCK ITEM316 if let AllowConstBlockItems::DoesNotMatter = allow_const_block_items {317 debug!("Parsing a const block item that does not matter: {:?}", self.token.span);318 };319 ItemKind::ConstBlock(self.parse_const_block_item()?)320 } else if let Const::Yes(const_span) = self.parse_constness(case) {321 // CONST ITEM322 self.recover_const_mut(const_span);323 self.recover_missing_kw_before_item()?;324 let (ident, generics, ty, rhs_kind) = self.parse_const_item(false, const_span)?;325 ItemKind::Const(Box::new(ConstItem {326 defaultness: def_(),327 ident,328 generics,329 ty,330 rhs_kind,331 define_opaque: None,332 }))333 } else if let Some(kind) = self.is_reuse_item() {334 self.parse_item_delegation(attrs, def_(), kind)?335 } else if self.check_keyword_case(exp!(Mod), case)336 || self.check_keyword_case(exp!(Unsafe), case) && self.is_keyword_ahead(1, &[kw::Mod])337 {338 // MODULE ITEM339 self.parse_item_mod(attrs)?340 } else if self.eat_keyword_case(exp!(Type), case) {341 if let Const::Yes(const_span) = self.parse_constness(case) {342 // TYPE CONST (mgca)343 self.recover_const_mut(const_span);344 self.recover_missing_kw_before_item()?;345 let (ident, generics, ty, rhs_kind) = self.parse_const_item(true, const_span)?;346 // Make sure this is only allowed if the feature gate is enabled.347 // #![feature(mgca_type_const_syntax)]348 self.psess.gated_spans.gate(sym::mgca_type_const_syntax, lo.to(const_span));349 ItemKind::Const(Box::new(ConstItem {350 defaultness: def_(),351 ident,352 generics,353 ty,354 rhs_kind,355 define_opaque: None,356 }))357 } else {358 // TYPE ITEM359 self.parse_type_alias(def_())?360 }361 } else if self.eat_keyword_case(exp!(Enum), case) {362 // ENUM ITEM363 self.parse_item_enum()?364 } else if self.eat_keyword_case(exp!(Struct), case) {365 // STRUCT ITEM366 self.parse_item_struct()?367 } else if self.is_kw_followed_by_ident(kw::Union) {368 // UNION ITEM369 self.bump(); // `union`370 self.parse_item_union()?371 } else if self.is_builtin() {372 // BUILTIN# ITEM373 return self.parse_item_builtin();374 } else if self.eat_keyword_case(exp!(Macro), case) {375 // MACROS 2.0 ITEM376 self.parse_item_decl_macro(lo)?377 } else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {378 // MACRO_RULES ITEM379 self.parse_item_macro_rules(vis, has_bang)?380 } else if self.isnt_macro_invocation()381 && (self.token.is_ident_named(sym::import)382 || self.token.is_ident_named(sym::using)383 || self.token.is_ident_named(sym::include)384 || self.token.is_ident_named(sym::require))385 {386 return self.recover_import_as_use();387 } else if self.isnt_macro_invocation() && vis.kind.is_pub() {388 self.recover_missing_kw_before_item()?;389 return Ok(None);390 } else if self.isnt_macro_invocation() && case == Case::Sensitive {391 _ = def_;392393 // Recover wrong cased keywords394 return self.parse_item_kind(395 attrs,396 macros_allowed,397 allow_const_block_items,398 lo,399 vis,400 def,401 fn_parse_mode,402 Case::Insensitive,403 );404 } else if macros_allowed && self.check_path() {405 if self.isnt_macro_invocation() {406 self.recover_missing_kw_before_item()?;407 }408 // MACRO INVOCATION ITEM409 ItemKind::MacCall(Box::new(self.parse_item_macro(vis)?))410 } else {411 return Ok(None);412 };413 Ok(Some(info))414 }415416 fn recover_import_as_use(&mut self) -> PResult<'a, Option<ItemKind>> {417 let span = self.token.span;418 let token_name = super::token_descr(&self.token);419 let snapshot = self.create_snapshot_for_diagnostic();420 self.bump();421 match self.parse_use_item() {422 Ok(u) => {423 self.dcx().emit_err(errors::RecoverImportAsUse { span, token_name });424 Ok(Some(u))425 }426 Err(e) => {427 e.cancel();428 self.restore_snapshot(snapshot);429 Ok(None)430 }431 }432 }433434 fn parse_use_item(&mut self) -> PResult<'a, ItemKind> {435 let tree = self.parse_use_tree()?;436 if let Err(mut e) = self.expect_semi() {437 match tree.kind {438 UseTreeKind::Glob(_) => {439 e.note("the wildcard token must be last on the path");440 }441 UseTreeKind::Nested { .. } => {442 e.note("glob-like brace syntax must be last on the path");443 }444 _ => (),445 }446 return Err(e);447 }448 Ok(ItemKind::Use(tree))449 }450451 /// When parsing a statement, would the start of a path be an item?452 pub(super) fn is_path_start_item(&mut self) -> bool {453 self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`454 || self.is_reuse_item().is_some() // yes: `reuse impl Trait for Struct { self.0 }`, yes: `reuse some_path::foo;`455 || self.check_trait_front_matter() // no: `auto::b`, yes: `auto trait X { .. }`456 || self.is_async_fn() // no(2015): `async::b`, yes: `async fn`457 || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac`458 }459460 fn is_reuse_item(&mut self) -> Option<ReuseKind> {461 if !self.token.is_keyword(kw::Reuse) {462 return None;463 }464465 // no: `reuse ::path` for compatibility reasons with macro invocations466 if self.look_ahead(1, |t| t.is_path_start() && *t != token::PathSep) {467 Some(ReuseKind::Path)468 } else if self.check_impl_frontmatter(1) {469 Some(ReuseKind::Impl)470 } else {471 None472 }473 }474475 /// Are we sure this could not possibly be a macro invocation?476 fn isnt_macro_invocation(&mut self) -> bool {477 self.check_ident() && self.look_ahead(1, |t| *t != token::Bang && *t != token::PathSep)478 }479480 /// Recover on encountering a struct, enum, or method definition where the user481 /// forgot to add the `struct`, `enum`, or `fn` keyword482 fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> {483 let is_pub = self.prev_token.is_keyword(kw::Pub);484 let is_const = self.prev_token.is_keyword(kw::Const);485 let ident_span = self.token.span;486 let span = if is_pub { self.prev_token.span.to(ident_span) } else { ident_span };487 let insert_span = ident_span.shrink_to_lo();488489 let ident = if self.token.is_ident()490 && (!is_const || self.look_ahead(1, |t| *t == token::OpenParen))491 && self.look_ahead(1, |t| {492 matches!(t.kind, token::Lt | token::OpenBrace | token::OpenParen)493 }) {494 self.parse_ident_common(true).unwrap()495 } else {496 return Ok(());497 };498499 let mut found_generics = false;500 if self.check(exp!(Lt)) {501 found_generics = true;502 self.eat_to_tokens(&[exp!(Gt)]);503 self.bump(); // `>`504 }505506 let err = if self.check(exp!(OpenBrace)) {507 // possible struct or enum definition where `struct` or `enum` was forgotten508 if self.look_ahead(1, |t| *t == token::CloseBrace) {509 // `S {}` could be unit enum or struct510 Some(errors::MissingKeywordForItemDefinition::EnumOrStruct { span })511 } else if self.look_ahead(2, |t| *t == token::Colon)512 || self.look_ahead(3, |t| *t == token::Colon)513 {514 // `S { f:` or `S { pub f:`515 Some(errors::MissingKeywordForItemDefinition::Struct { span, insert_span, ident })516 } else {517 Some(errors::MissingKeywordForItemDefinition::Enum { span, insert_span, ident })518 }519 } else if self.check(exp!(OpenParen)) {520 // possible function or tuple struct definition where `fn` or `struct` was forgotten521 self.bump(); // `(`522 let is_method = self.recover_self_param();523524 self.consume_block(exp!(OpenParen), exp!(CloseParen), ConsumeClosingDelim::Yes);525526 let err = if self.check(exp!(RArrow)) || self.check(exp!(OpenBrace)) {527 self.eat_to_tokens(&[exp!(OpenBrace)]);528 self.bump(); // `{`529 self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);530 if is_method {531 errors::MissingKeywordForItemDefinition::Method { span, insert_span, ident }532 } else {533 errors::MissingKeywordForItemDefinition::Function { span, insert_span, ident }534 }535 } else if is_pub && self.check(exp!(Semi)) {536 errors::MissingKeywordForItemDefinition::Struct { span, insert_span, ident }537 } else {538 errors::MissingKeywordForItemDefinition::Ambiguous {539 span,540 subdiag: if found_generics {541 None542 } else if let Ok(snippet) = self.span_to_snippet(ident_span) {543 Some(errors::AmbiguousMissingKwForItemSub::SuggestMacro {544 span: ident_span,545 snippet,546 })547 } else {548 Some(errors::AmbiguousMissingKwForItemSub::HelpMacro)549 },550 }551 };552 Some(err)553 } else if found_generics {554 Some(errors::MissingKeywordForItemDefinition::Ambiguous { span, subdiag: None })555 } else {556 None557 };558559 if let Some(err) = err { Err(self.dcx().create_err(err)) } else { Ok(()) }560 }561562 fn parse_item_builtin(&mut self) -> PResult<'a, Option<ItemKind>> {563 // To be expanded564 Ok(None)565 }566567 /// Parses an item macro, e.g., `item!();`.568 fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> {569 let path = self.parse_path(PathStyle::Mod)?; // `foo::bar`570 self.expect(exp!(Bang))?; // `!`571 match self.parse_delim_args() {572 // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`.573 Ok(args) => {574 self.eat_semi_for_macro_if_needed(&args, Some(&path));575 self.complain_if_pub_macro(vis, false);576 Ok(MacCall { path, args })577 }578579 Err(mut err) => {580 // Maybe the user misspelled `macro_rules` (issue #91227)581 if self.token.is_ident()582 && let [segment] = path.segments.as_slice()583 && edit_distance("macro_rules", &segment.ident.to_string(), 2).is_some()584 {585 err.span_suggestion(586 path.span,587 "perhaps you meant to define a macro",588 "macro_rules",589 Applicability::MachineApplicable,590 );591 }592 Err(err)593 }594 }595 }596597 /// Recover if we parsed attributes and expected an item but there was none.598 fn recover_attrs_no_item(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> {599 let ([start @ end] | [start, .., end]) = attrs else {600 return Ok(());601 };602 let msg = if end.is_doc_comment() {603 "expected item after doc comment"604 } else {605 "expected item after attributes"606 };607 let mut err = self.dcx().struct_span_err(end.span, msg);608 if end.is_doc_comment() {609 err.span_label(end.span, "this doc comment doesn't document anything");610 } else if self.token == TokenKind::Semi {611 err.span_suggestion_verbose(612 self.token.span,613 "consider removing this semicolon",614 "",615 Applicability::MaybeIncorrect,616 );617 }618 if let [.., penultimate, _] = attrs {619 err.span_label(start.span.to(penultimate.span), "other attributes here");620 }621 Err(err)622 }623624 fn is_async_fn(&self) -> bool {625 self.token.is_keyword(kw::Async) && self.is_keyword_ahead(1, &[kw::Fn])626 }627628 fn parse_polarity(&mut self) -> ast::ImplPolarity {629 // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.630 if self.check(exp!(Bang)) && self.look_ahead(1, |t| t.can_begin_type()) {631 self.psess.gated_spans.gate(sym::negative_impls, self.token.span);632 self.bump(); // `!`633 ast::ImplPolarity::Negative(self.prev_token.span)634 } else {635 ast::ImplPolarity::Positive636 }637 }638639 /// Parses an implementation item.640 ///641 /// ```ignore (illustrative)642 /// impl<'a, T> TYPE { /* impl items */ }643 /// impl<'a, T> TRAIT for TYPE { /* impl items */ }644 /// impl<'a, T> !TRAIT for TYPE { /* impl items */ }645 /// impl<'a, T> const TRAIT for TYPE { /* impl items */ }646 /// ```647 ///648 /// We actually parse slightly more relaxed grammar for better error reporting and recovery.649 /// ```ebnf650 /// "impl" GENERICS "const"? "!"? TYPE "for"? (TYPE | "..") ("where" PREDICATES)? "{" BODY "}"651 /// "impl" GENERICS "const"? "!"? TYPE ("where" PREDICATES)? "{" BODY "}"652 /// ```653 fn parse_item_impl(654 &mut self,655 attrs: &mut AttrVec,656 defaultness: Defaultness,657 is_reuse: bool,658 ) -> PResult<'a, ItemKind> {659 let mut constness = self.parse_constness(Case::Sensitive);660 let safety = self.parse_safety(Case::Sensitive);661 self.expect_keyword(exp!(Impl))?;662663 // First, parse generic parameters if necessary.664 let mut generics = if self.choose_generics_over_qpath(0) {665 self.parse_generics()?666 } else {667 let mut generics = Generics::default();668 // impl A for B {}669 // /\ this is where `generics.span` should point when there are no type params.670 generics.span = self.prev_token.span.shrink_to_hi();671 generics672 };673674 if let Const::No = constness {675 // FIXME(const_trait_impl): disallow `impl const Trait`676 constness = self.parse_constness(Case::Sensitive);677 }678679 if let Const::Yes(span) = constness {680 self.psess.gated_spans.gate(sym::const_trait_impl, span);681 }682683 // Parse stray `impl async Trait`684 if (self.token_uninterpolated_span().at_least_rust_2018()685 && self.token.is_keyword(kw::Async))686 || self.is_kw_followed_by_ident(kw::Async)687 {688 self.bump();689 self.dcx().emit_err(errors::AsyncImpl { span: self.prev_token.span });690 }691692 let polarity = self.parse_polarity();693694 // Parse both types and traits as a type, then reinterpret if necessary.695 let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt)696 {697 let span = self.prev_token.span.between(self.token.span);698 return Err(self.dcx().create_err(errors::MissingTraitInTraitImpl {699 span,700 for_span: span.to(self.token.span),701 }));702 } else {703 self.parse_ty_with_generics_recovery(&generics)?704 };705706 // If `for` is missing we try to recover.707 let has_for = self.eat_keyword(exp!(For));708 let missing_for_span = self.prev_token.span.between(self.token.span);709710 let ty_second = if self.token == token::DotDot {711 // We need to report this error after `cfg` expansion for compatibility reasons712 self.bump(); // `..`, do not add it to expected tokens713714 // AST validation later detects this `TyKind::Dummy` and emits an715 // error. (#121072 will hopefully remove all this special handling716 // of the obsolete `impl Trait for ..` and then this can go away.)717 Some(self.mk_ty(self.prev_token.span, TyKind::Dummy))718 } else if has_for || self.token.can_begin_type() {719 Some(self.parse_ty()?)720 } else {721 None722 };723724 generics.where_clause = self.parse_where_clause()?;725726 let impl_items = if is_reuse {727 Default::default()728 } else {729 self.parse_item_list(attrs, |p| p.parse_impl_item(ForceCollect::No))?730 };731732 let (of_trait, self_ty) = match ty_second {733 Some(ty_second) => {734 // impl Trait for Type735 if !has_for {736 self.dcx().emit_err(errors::MissingForInTraitImpl { span: missing_for_span });737 }738739 let ty_first = *ty_first;740 let path = match ty_first.kind {741 // This notably includes paths passed through `ty` macro fragments (#46438).742 TyKind::Path(None, path) => path,743 other => {744 if let TyKind::ImplTrait(_, bounds) = other745 && let [bound] = bounds.as_slice()746 && let GenericBound::Trait(poly_trait_ref) = bound747 {748 // Suggest removing extra `impl` keyword:749 // `impl<T: Default> impl Default for Wrapper<T>`750 // ^^^^^751 let extra_impl_kw = ty_first.span.until(bound.span());752 self.dcx().emit_err(errors::ExtraImplKeywordInTraitImpl {753 extra_impl_kw,754 impl_trait_span: ty_first.span,755 });756 poly_trait_ref.trait_ref.path.clone()757 } else {758 return Err(self.dcx().create_err(759 errors::ExpectedTraitInTraitImplFoundType { span: ty_first.span },760 ));761 }762 }763 };764 let trait_ref = TraitRef { path, ref_id: ty_first.id };765766 let of_trait =767 Some(Box::new(TraitImplHeader { defaultness, safety, polarity, trait_ref }));768 (of_trait, ty_second)769 }770 None => {771 let self_ty = ty_first;772 let error = |modifier, modifier_name, modifier_span| {773 self.dcx().create_err(errors::TraitImplModifierInInherentImpl {774 span: self_ty.span,775 modifier,776 modifier_name,777 modifier_span,778 self_ty: self_ty.span,779 })780 };781782 if let Safety::Unsafe(span) = safety {783 error("unsafe", "unsafe", span).with_code(E0197).emit();784 }785 if let ImplPolarity::Negative(span) = polarity {786 error("!", "negative", span).emit();787 }788 if let Defaultness::Default(def_span) = defaultness {789 error("default", "default", def_span).emit();790 }791 if let Const::Yes(span) = constness {792 self.psess.gated_spans.gate(sym::const_trait_impl, span);793 }794 (None, self_ty)795 }796 };797798 Ok(ItemKind::Impl(Impl { generics, of_trait, self_ty, items: impl_items, constness }))799 }800801 fn parse_item_delegation(802 &mut self,803 attrs: &mut AttrVec,804 defaultness: Defaultness,805 kind: ReuseKind,806 ) -> PResult<'a, ItemKind> {807 let span = self.token.span;808 self.expect_keyword(exp!(Reuse))?;809810 let item_kind = match kind {811 ReuseKind::Path => self.parse_path_like_delegation(),812 ReuseKind::Impl => self.parse_impl_delegation(span, attrs, defaultness),813 }?;814815 self.psess.gated_spans.gate(sym::fn_delegation, span.to(self.prev_token.span));816817 Ok(item_kind)818 }819820 fn parse_delegation_body(&mut self) -> PResult<'a, Option<Box<Block>>> {821 Ok(if self.check(exp!(OpenBrace)) {822 Some(self.parse_block()?)823 } else {824 self.expect(exp!(Semi))?;825 None826 })827 }828829 fn parse_impl_delegation(830 &mut self,831 span: Span,832 attrs: &mut AttrVec,833 defaultness: Defaultness,834 ) -> PResult<'a, ItemKind> {835 let mut impl_item = self.parse_item_impl(attrs, defaultness, true)?;836 let ItemKind::Impl(Impl { items, of_trait, .. }) = &mut impl_item else { unreachable!() };837838 let until_expr_span = span.to(self.prev_token.span);839840 let Some(of_trait) = of_trait else {841 return Err(self842 .dcx()843 .create_err(errors::ImplReuseInherentImpl { span: until_expr_span }));844 };845846 let body = self.parse_delegation_body()?;847 let whole_reuse_span = span.to(self.prev_token.span);848849 items.push(Box::new(AssocItem {850 id: DUMMY_NODE_ID,851 attrs: Default::default(),852 span: whole_reuse_span,853 tokens: None,854 vis: Visibility {855 kind: VisibilityKind::Inherited,856 span: whole_reuse_span,857 tokens: None,858 },859 kind: AssocItemKind::DelegationMac(Box::new(DelegationMac {860 qself: None,861 prefix: of_trait.trait_ref.path.clone(),862 suffixes: DelegationSuffixes::Glob(whole_reuse_span),863 body,864 })),865 }));866867 Ok(impl_item)868 }869870 fn parse_path_like_delegation(&mut self) -> PResult<'a, ItemKind> {871 let (qself, path) = if self.eat_lt() {872 let (qself, path) = self.parse_qpath(PathStyle::Expr)?;873 (Some(qself), path)874 } else {875 (None, self.parse_path(PathStyle::Expr)?)876 };877878 let rename = |this: &mut Self| {879 Ok(if this.eat_keyword(exp!(As)) { Some(this.parse_ident()?) } else { None })880 };881882 Ok(if self.eat_path_sep() {883 let suffixes = if self.eat(exp!(Star)) {884 DelegationSuffixes::Glob(self.prev_token.span)885 } else {886 let parse_suffix = |p: &mut Self| Ok((p.parse_path_segment_ident()?, rename(p)?));887 DelegationSuffixes::List(888 self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), parse_suffix)?.0,889 )890 };891892 ItemKind::DelegationMac(Box::new(DelegationMac {893 qself,894 prefix: path,895 suffixes,896 body: self.parse_delegation_body()?,897 }))898 } else {899 let rename = rename(self)?;900 let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);901902 ItemKind::Delegation(Box::new(Delegation {903 id: DUMMY_NODE_ID,904 qself,905 path,906 ident,907 rename,908 body: self.parse_delegation_body()?,909 from_glob: false,910 }))911 })912 }913914 fn parse_item_list<T>(915 &mut self,916 attrs: &mut AttrVec,917 mut parse_item: impl FnMut(&mut Parser<'a>) -> PResult<'a, Option<Option<T>>>,918 ) -> PResult<'a, ThinVec<T>> {919 let open_brace_span = self.token.span;920921 // Recover `impl Ty;` instead of `impl Ty {}`922 if self.token == TokenKind::Semi {923 self.dcx().emit_err(errors::UseEmptyBlockNotSemi { span: self.token.span });924 self.bump();925 return Ok(ThinVec::new());926 }927928 self.expect(exp!(OpenBrace))?;929 attrs.extend(self.parse_inner_attributes()?);930931 let mut items = ThinVec::new();932 while !self.eat(exp!(CloseBrace)) {933 if self.recover_doc_comment_before_brace() {934 continue;935 }936 self.recover_vcs_conflict_marker();937 match parse_item(self) {938 Ok(None) => {939 let mut is_unnecessary_semicolon = !items.is_empty()940 // When the close delim is `)` in a case like the following, `token.kind`941 // is expected to be `token::CloseParen`, but the actual `token.kind` is942 // `token::CloseBrace`. This is because the `token.kind` of the close delim943 // is treated as the same as that of the open delim in944 // `TokenTreesReader::parse_token_tree`, even if the delimiters of them are945 // different. Therefore, `token.kind` should not be compared here.946 //947 // issue-60075.rs948 // ```949 // trait T {950 // fn qux() -> Option<usize> {951 // let _ = if true {952 // });953 // ^ this close delim954 // Some(4)955 // }956 // ```957 && self958 .span_to_snippet(self.prev_token.span)959 .is_ok_and(|snippet| snippet == "}")960 && self.token == token::Semi;961 let mut semicolon_span = self.token.span;962 if !is_unnecessary_semicolon {963 // #105369, Detect spurious `;` before assoc fn body964 is_unnecessary_semicolon =965 self.token == token::OpenBrace && self.prev_token == token::Semi;966 semicolon_span = self.prev_token.span;967 }968 // We have to bail or we'll potentially never make progress.969 let non_item_span = self.token.span;970 let is_let = self.token.is_keyword(kw::Let);971972 let mut err =973 self.dcx().struct_span_err(non_item_span, "non-item in item list");974 self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);975 if is_let {976 err.span_suggestion_verbose(977 non_item_span,978 "consider using `const` instead of `let` for associated const",979 "const",980 Applicability::MachineApplicable,981 );982 } else {983 err.span_label(open_brace_span, "item list starts here")984 .span_label(non_item_span, "non-item starts here")985 .span_label(self.prev_token.span, "item list ends here");986 }987 if is_unnecessary_semicolon {988 err.span_suggestion(989 semicolon_span,990 "consider removing this semicolon",991 "",992 Applicability::MaybeIncorrect,993 );994 }995 err.emit();996 break;997 }998 Ok(Some(item)) => items.extend(item),999 Err(err) => {1000 self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);1001 err.with_span_label(1002 open_brace_span,1003 "while parsing this item list starting here",1004 )1005 .with_span_label(self.prev_token.span, "the item list ends here")1006 .emit();1007 break;1008 }1009 }1010 }1011 Ok(items)1012 }10131014 /// Recover on a doc comment before `}`.1015 fn recover_doc_comment_before_brace(&mut self) -> bool {1016 if let token::DocComment(..) = self.token.kind {1017 if self.look_ahead(1, |tok| tok == &token::CloseBrace) {1018 // FIXME: merge with `DocCommentDoesNotDocumentAnything` (E0585)1019 struct_span_code_err!(1020 self.dcx(),1021 self.token.span,1022 E0584,1023 "found a documentation comment that doesn't document anything",1024 )1025 .with_span_label(self.token.span, "this doc comment doesn't document anything")1026 .with_help(1027 "doc comments must come before what they document, if a comment was \1028 intended use `//`",1029 )1030 .emit();1031 self.bump();1032 return true;1033 }1034 }1035 false1036 }10371038 /// Parses defaultness (i.e., `default` or nothing).1039 fn parse_defaultness(&mut self) -> Defaultness {1040 // We are interested in `default` followed by another identifier.1041 // However, we must avoid keywords that occur as binary operators.1042 // Currently, the only applicable keyword is `as` (`default as Ty`).1043 if self.check_keyword(exp!(Default))1044 && self.look_ahead(1, |t| t.is_non_raw_ident_where(|i| i.name != kw::As))1045 {1046 self.psess.gated_spans.gate(sym::specialization, self.token.span);1047 self.bump(); // `default`1048 Defaultness::Default(self.prev_token_uninterpolated_span())1049 } else if self.eat_keyword(exp!(Final)) {1050 self.psess.gated_spans.gate(sym::final_associated_functions, self.prev_token.span);1051 Defaultness::Final(self.prev_token_uninterpolated_span())1052 } else {1053 Defaultness::Implicit1054 }1055 }10561057 /// Is this an `[impl(in? path)]? const? unsafe? auto? trait` item?1058 fn check_trait_front_matter(&mut self) -> bool {1059 const SUFFIXES: &[&[Symbol]] = &[1060 &[kw::Trait],1061 &[kw::Auto, kw::Trait],1062 &[kw::Unsafe, kw::Trait],1063 &[kw::Unsafe, kw::Auto, kw::Trait],1064 &[kw::Const, kw::Trait],1065 &[kw::Const, kw::Auto, kw::Trait],1066 &[kw::Const, kw::Unsafe, kw::Trait],1067 &[kw::Const, kw::Unsafe, kw::Auto, kw::Trait],1068 ];1069 // `impl(`1070 if self.check_keyword(exp!(Impl)) && self.look_ahead(1, |t| t == &token::OpenParen) {1071 // `impl(in` unambiguously introduces an `impl` restriction1072 if self.is_keyword_ahead(2, &[kw::In]) {1073 return true;1074 }1075 // `impl(crate | self | super)` + SUFFIX1076 if self.is_keyword_ahead(2, &[kw::Crate, kw::SelfLower, kw::Super])1077 && self.look_ahead(3, |t| t == &token::CloseParen)1078 && SUFFIXES.iter().any(|suffix| {1079 suffix.iter().enumerate().all(|(i, kw)| self.is_keyword_ahead(i + 4, &[*kw]))1080 })1081 {1082 return true;1083 }1084 // Recover cases like `impl(path::to::module)` + SUFFIX to suggest inserting `in`.1085 SUFFIXES.iter().any(|suffix| {1086 suffix.iter().enumerate().all(|(i, kw)| {1087 self.tree_look_ahead(i + 2, |t| {1088 if let TokenTree::Token(token, _) = t {1089 token.is_keyword(*kw)1090 } else {1091 false1092 }1093 })1094 .unwrap_or(false)1095 })1096 })1097 } else {1098 SUFFIXES.iter().any(|suffix| {1099 suffix.iter().enumerate().all(|(i, kw)| {1100 // We use `check_keyword` for the first token to include it in the expected tokens.1101 if i == 0 {1102 match *kw {1103 kw::Const => self.check_keyword(exp!(Const)),1104 kw::Unsafe => self.check_keyword(exp!(Unsafe)),1105 kw::Auto => self.check_keyword(exp!(Auto)),1106 kw::Trait => self.check_keyword(exp!(Trait)),1107 _ => unreachable!(),1108 }1109 } else {1110 self.is_keyword_ahead(i, &[*kw])1111 }1112 })1113 })1114 }1115 }11161117 /// Parses `[impl(in? path)]? const? unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`.1118 fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemKind> {1119 let impl_restriction = self.parse_impl_restriction()?;1120 let constness = self.parse_constness(Case::Sensitive);1121 if let Const::Yes(span) = constness {1122 self.psess.gated_spans.gate(sym::const_trait_impl, span);1123 }1124 let safety = self.parse_safety(Case::Sensitive);1125 // Parse optional `auto` prefix.1126 let is_auto = if self.eat_keyword(exp!(Auto)) {1127 self.psess.gated_spans.gate(sym::auto_traits, self.prev_token.span);1128 IsAuto::Yes1129 } else {1130 IsAuto::No1131 };11321133 self.expect_keyword(exp!(Trait))?;1134 let ident = self.parse_ident()?;1135 let mut generics = self.parse_generics()?;11361137 // Parse optional colon and supertrait bounds.1138 let had_colon = self.eat(exp!(Colon));1139 let span_at_colon = self.prev_token.span;1140 let bounds = if had_colon { self.parse_generic_bounds()? } else { Vec::new() };11411142 let span_before_eq = self.prev_token.span;1143 if self.eat(exp!(Eq)) {1144 // It's a trait alias.1145 if had_colon {1146 let span = span_at_colon.to(span_before_eq);1147 self.dcx().emit_err(errors::BoundsNotAllowedOnTraitAliases { span });1148 }11491150 let bounds = self.parse_generic_bounds()?;1151 generics.where_clause = self.parse_where_clause()?;1152 self.expect_semi()?;11531154 let whole_span = lo.to(self.prev_token.span);1155 if is_auto == IsAuto::Yes {1156 self.dcx().emit_err(errors::TraitAliasCannotBeAuto { span: whole_span });1157 }1158 if let Safety::Unsafe(_) = safety {1159 self.dcx().emit_err(errors::TraitAliasCannotBeUnsafe { span: whole_span });1160 }1161 if let RestrictionKind::Restricted { .. } = impl_restriction.kind {1162 self.dcx().emit_err(errors::TraitAliasCannotBeImplRestricted { span: whole_span });1163 }11641165 self.psess.gated_spans.gate(sym::trait_alias, whole_span);11661167 Ok(ItemKind::TraitAlias(Box::new(TraitAlias { constness, ident, generics, bounds })))1168 } else {1169 // It's a normal trait.1170 generics.where_clause = self.parse_where_clause()?;1171 let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?;1172 Ok(ItemKind::Trait(Box::new(Trait {1173 impl_restriction,1174 constness,1175 is_auto,1176 safety,1177 ident,1178 generics,1179 bounds,1180 items,1181 })))1182 }1183 }11841185 pub fn parse_impl_item(1186 &mut self,1187 force_collect: ForceCollect,1188 ) -> PResult<'a, Option<Option<Box<AssocItem>>>> {1189 let fn_parse_mode =1190 FnParseMode { req_name: |_, _| true, context: FnContext::Impl, req_body: true };1191 self.parse_assoc_item(fn_parse_mode, force_collect)1192 }11931194 pub fn parse_trait_item(1195 &mut self,1196 force_collect: ForceCollect,1197 ) -> PResult<'a, Option<Option<Box<AssocItem>>>> {1198 let fn_parse_mode = FnParseMode {1199 req_name: |edition, _| edition >= Edition::Edition2018,1200 context: FnContext::Trait,1201 req_body: false,1202 };1203 self.parse_assoc_item(fn_parse_mode, force_collect)1204 }12051206 /// Parses associated items.1207 fn parse_assoc_item(1208 &mut self,1209 fn_parse_mode: FnParseMode,1210 force_collect: ForceCollect,1211 ) -> PResult<'a, Option<Option<Box<AssocItem>>>> {1212 Ok(self1213 .parse_item_(1214 fn_parse_mode,1215 force_collect,1216 AllowConstBlockItems::DoesNotMatter, // due to `AssocItemKind::try_from` below1217 )?1218 .map(|Item { attrs, id, span, vis, kind, tokens }| {1219 let kind = match AssocItemKind::try_from(kind) {1220 Ok(kind) => kind,1221 Err(kind) => match kind {1222 ItemKind::Static(box StaticItem {1223 ident,1224 ty,1225 safety: _,1226 mutability: _,1227 expr,1228 define_opaque,1229 eii_impls: _,1230 }) => {1231 self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span });1232 AssocItemKind::Const(Box::new(ConstItem {1233 defaultness: Defaultness::Implicit,1234 ident,1235 generics: Generics::default(),1236 ty,1237 rhs_kind: ConstItemRhsKind::Body { rhs: expr },1238 define_opaque,1239 }))1240 }1241 _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"),1242 },1243 };1244 Some(Box::new(Item { attrs, id, span, vis, kind, tokens }))1245 }))1246 }12471248 /// Parses a `type` alias with the following grammar:1249 /// ```ebnf1250 /// TypeAlias = "type" Ident Generics (":" GenericBounds)? WhereClause ("=" Ty)? WhereClause ";" ;1251 /// ```1252 /// The `"type"` has already been eaten.1253 fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemKind> {1254 let ident = self.parse_ident()?;1255 let mut generics = self.parse_generics()?;12561257 // Parse optional colon and param bounds.1258 let bounds = if self.eat(exp!(Colon)) { self.parse_generic_bounds()? } else { Vec::new() };1259 generics.where_clause = self.parse_where_clause()?;12601261 let ty = if self.eat(exp!(Eq)) { Some(self.parse_ty()?) } else { None };12621263 let after_where_clause = self.parse_where_clause()?;12641265 self.expect_semi()?;12661267 Ok(ItemKind::TyAlias(Box::new(TyAlias {1268 defaultness,1269 ident,1270 generics,1271 after_where_clause,1272 bounds,1273 ty,1274 })))1275 }12761277 /// Parses a `UseTree`.1278 ///1279 /// ```text1280 /// USE_TREE = [`::`] `*` |1281 /// [`::`] `{` USE_TREE_LIST `}` |1282 /// PATH `::` `*` |1283 /// PATH `::` `{` USE_TREE_LIST `}` |1284 /// PATH [`as` IDENT]1285 /// ```1286 fn parse_use_tree(&mut self) -> PResult<'a, UseTree> {1287 let lo = self.token.span;12881289 let mut prefix =1290 ast::Path { segments: ThinVec::new(), span: lo.shrink_to_lo(), tokens: None };1291 let kind =1292 if self.check(exp!(OpenBrace)) || self.check(exp!(Star)) || self.is_import_coupler() {1293 // `use *;` or `use ::*;` or `use {...};` or `use ::{...};`1294 let mod_sep_ctxt = self.token.span.ctxt();1295 if self.eat_path_sep() {1296 prefix1297 .segments1298 .push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));1299 }13001301 self.parse_use_tree_glob_or_nested()?1302 } else {1303 // `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;`1304 prefix = self.parse_path(PathStyle::Mod)?;13051306 if self.eat_path_sep() {1307 self.parse_use_tree_glob_or_nested()?1308 } else {1309 // Recover from using a colon as path separator.1310 while self.eat_noexpect(&token::Colon) {1311 self.dcx()1312 .emit_err(errors::SingleColonImportPath { span: self.prev_token.span });13131314 // We parse the rest of the path and append it to the original prefix.1315 self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None)?;1316 prefix.span = lo.to(self.prev_token.span);1317 }13181319 UseTreeKind::Simple(self.parse_rename()?)1320 }1321 };13221323 Ok(UseTree { prefix, kind })1324 }13251326 /// Parses `*` or `{...}`.1327 fn parse_use_tree_glob_or_nested(&mut self) -> PResult<'a, UseTreeKind> {1328 Ok(if self.eat(exp!(Star)) {1329 UseTreeKind::Glob(self.prev_token.span)1330 } else {1331 let lo = self.token.span;1332 UseTreeKind::Nested {1333 items: self.parse_use_tree_list()?,1334 span: lo.to(self.prev_token.span),1335 }1336 })1337 }13381339 /// Parses a `UseTreeKind::Nested(list)`.1340 ///1341 /// ```text1342 /// USE_TREE_LIST = ∅ | (USE_TREE `,`)* USE_TREE [`,`]1343 /// ```1344 fn parse_use_tree_list(&mut self) -> PResult<'a, ThinVec<(UseTree, ast::NodeId)>> {1345 self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), |p| {1346 p.recover_vcs_conflict_marker();1347 Ok((p.parse_use_tree()?, DUMMY_NODE_ID))1348 })1349 .map(|(r, _)| r)1350 }13511352 fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {1353 if self.eat_keyword(exp!(As)) {1354 self.parse_ident_or_underscore().map(Some)1355 } else {1356 Ok(None)1357 }1358 }13591360 fn parse_ident_or_underscore(&mut self) -> PResult<'a, Ident> {1361 match self.token.ident() {1362 Some((ident @ Ident { name: kw::Underscore, .. }, IdentIsRaw::No)) => {1363 self.bump();1364 Ok(ident)1365 }1366 _ => self.parse_ident(),1367 }1368 }13691370 /// Parses `extern crate` links.1371 ///1372 /// # Examples1373 ///1374 /// ```ignore (illustrative)1375 /// extern crate foo;1376 /// extern crate bar as foo;1377 /// ```1378 fn parse_item_extern_crate(&mut self) -> PResult<'a, ItemKind> {1379 // Accept `extern crate name-like-this` for better diagnostics1380 let orig_ident = self.parse_crate_name_with_dashes()?;1381 let (orig_name, item_ident) = if let Some(rename) = self.parse_rename()? {1382 (Some(orig_ident.name), rename)1383 } else {1384 (None, orig_ident)1385 };1386 self.expect_semi()?;1387 Ok(ItemKind::ExternCrate(orig_name, item_ident))1388 }13891390 fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, Ident> {1391 let ident = if self.token.is_keyword(kw::SelfLower) {1392 self.parse_path_segment_ident()1393 } else {1394 self.parse_ident()1395 }?;13961397 let dash = exp!(Minus);1398 if self.token != dash.tok {1399 return Ok(ident);1400 }14011402 // Accept `extern crate name-like-this` for better diagnostics.1403 let mut dashes = vec![];1404 let mut idents = vec![];1405 while self.eat(dash) {1406 dashes.push(self.prev_token.span);1407 idents.push(self.parse_ident()?);1408 }14091410 let fixed_name_sp = ident.span.to(idents.last().unwrap().span);1411 let mut fixed_name = ident.name.to_string();1412 for part in idents {1413 write!(fixed_name, "_{}", part.name).unwrap();1414 }14151416 self.dcx().emit_err(errors::ExternCrateNameWithDashes {1417 span: fixed_name_sp,1418 sugg: errors::ExternCrateNameWithDashesSugg { dashes },1419 });14201421 Ok(Ident::from_str_and_span(&fixed_name, fixed_name_sp))1422 }14231424 /// Parses `extern` for foreign ABIs modules.1425 ///1426 /// `extern` is expected to have been consumed before calling this method.1427 ///1428 /// # Examples1429 ///1430 /// ```ignore (only-for-syntax-highlight)1431 /// extern "C" {}1432 /// extern {}1433 /// ```1434 fn parse_item_foreign_mod(1435 &mut self,1436 attrs: &mut AttrVec,1437 mut safety: Safety,1438 ) -> PResult<'a, ItemKind> {1439 let extern_span = self.prev_token_uninterpolated_span();1440 let abi = self.parse_abi(); // ABI?1441 // FIXME: This recovery should be tested better.1442 if safety == Safety::Default1443 && self.token.is_keyword(kw::Unsafe)1444 && self.look_ahead(1, |t| *t == token::OpenBrace)1445 {1446 self.expect(exp!(OpenBrace)).unwrap_err().emit();1447 safety = Safety::Unsafe(self.token.span);1448 let _ = self.eat_keyword(exp!(Unsafe));1449 }1450 Ok(ItemKind::ForeignMod(ast::ForeignMod {1451 extern_span,1452 safety,1453 abi,1454 items: self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?,1455 }))1456 }14571458 /// Parses a foreign item (one in an `extern { ... }` block).1459 pub fn parse_foreign_item(1460 &mut self,1461 force_collect: ForceCollect,1462 ) -> PResult<'a, Option<Option<Box<ForeignItem>>>> {1463 let fn_parse_mode = FnParseMode {1464 req_name: |_, is_dot_dot_dot| is_dot_dot_dot == IsDotDotDot::No,1465 context: FnContext::Free,1466 req_body: false,1467 };1468 Ok(self1469 .parse_item_(1470 fn_parse_mode,1471 force_collect,1472 AllowConstBlockItems::DoesNotMatter, // due to `ForeignItemKind::try_from` below1473 )?1474 .map(|Item { attrs, id, span, vis, kind, tokens }| {1475 let kind = match ForeignItemKind::try_from(kind) {1476 Ok(kind) => kind,1477 Err(kind) => match kind {1478 ItemKind::Const(box ConstItem { ident, ty, rhs_kind, .. }) => {1479 let const_span = Some(span.with_hi(ident.span.lo()))1480 .filter(|span| span.can_be_used_for_suggestions());1481 self.dcx().emit_err(errors::ExternItemCannotBeConst {1482 ident_span: ident.span,1483 const_span,1484 });1485 ForeignItemKind::Static(Box::new(StaticItem {1486 ident,1487 ty,1488 mutability: Mutability::Not,1489 expr: match rhs_kind {1490 ConstItemRhsKind::Body { rhs } => rhs,1491 ConstItemRhsKind::TypeConst { rhs: Some(anon) } => {1492 Some(anon.value)1493 }1494 ConstItemRhsKind::TypeConst { rhs: None } => None,1495 },1496 safety: Safety::Default,1497 define_opaque: None,1498 eii_impls: ThinVec::default(),1499 }))1500 }1501 _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"),1502 },1503 };1504 Some(Box::new(Item { attrs, id, span, vis, kind, tokens }))1505 }))1506 }15071508 fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &'static str) -> Option<T> {1509 // FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`)1510 let span = self.psess.source_map().guess_head_span(span);1511 let descr = kind.descr();1512 let help = match kind {1513 ItemKind::DelegationMac(box DelegationMac {1514 suffixes: DelegationSuffixes::Glob(_),1515 ..1516 }) => false,1517 _ => true,1518 };1519 self.dcx().emit_err(errors::BadItemKind { span, descr, ctx, help });1520 None1521 }15221523 fn is_use_closure(&self) -> bool {1524 if self.token.is_keyword(kw::Use) {1525 // Check if this could be a closure.1526 self.look_ahead(1, |token| {1527 // Move or Async here would be an error but still we're parsing a closure1528 let dist =1529 if token.is_keyword(kw::Move) || token.is_keyword(kw::Async) { 2 } else { 1 };15301531 self.look_ahead(dist, |token| matches!(token.kind, token::Or | token::OrOr))1532 })1533 } else {1534 false1535 }1536 }15371538 fn is_unsafe_foreign_mod(&self) -> bool {1539 // Look for `unsafe`.1540 if !self.token.is_keyword(kw::Unsafe) {1541 return false;1542 }1543 // Look for `extern`.1544 if !self.is_keyword_ahead(1, &[kw::Extern]) {1545 return false;1546 }15471548 // Look for the optional ABI string literal.1549 let n = if self.look_ahead(2, |t| t.can_begin_string_literal()) { 3 } else { 2 };15501551 // Look for the `{`. Use `tree_look_ahead` because the ABI (if present)1552 // might be a metavariable i.e. an invisible-delimited sequence, and1553 // `tree_look_ahead` will consider that a single element when looking1554 // ahead.1555 self.tree_look_ahead(n, |t| matches!(t, TokenTree::Delimited(_, _, Delimiter::Brace, _)))1556 == Some(true)1557 }15581559 fn parse_global_static_front_matter(&mut self, case: Case) -> Option<Safety> {1560 let is_global_static = if self.check_keyword_case(exp!(Static), case) {1561 // Check if this could be a closure.1562 !self.look_ahead(1, |token| {1563 if token.is_keyword_case(kw::Move, case) || token.is_keyword_case(kw::Use, case) {1564 return true;1565 }1566 matches!(token.kind, token::Or | token::OrOr)1567 })1568 } else {1569 // `$qual static`1570 (self.check_keyword_case(exp!(Unsafe), case)1571 || self.check_keyword_case(exp!(Safe), case))1572 && self.look_ahead(1, |t| t.is_keyword_case(kw::Static, case))1573 };15741575 if is_global_static {1576 let safety = self.parse_safety(case);1577 let _ = self.eat_keyword_case(exp!(Static), case);1578 Some(safety)1579 } else {1580 None1581 }1582 }15831584 /// Recover on `const mut` with `const` already eaten.1585 fn recover_const_mut(&mut self, const_span: Span) {1586 if self.eat_keyword(exp!(Mut)) {1587 let span = self.prev_token.span;1588 self.dcx()1589 .emit_err(errors::ConstGlobalCannotBeMutable { ident_span: span, const_span });1590 } else if self.eat_keyword(exp!(Let)) {1591 let span = self.prev_token.span;1592 self.dcx().emit_err(errors::ConstLetMutuallyExclusive { span: const_span.to(span) });1593 }1594 }15951596 fn parse_const_block_item(&mut self) -> PResult<'a, ConstBlockItem> {1597 self.expect_keyword(exp!(Const))?;1598 let const_span = self.prev_token.span;1599 self.psess.gated_spans.gate(sym::const_block_items, const_span);1600 let block = self.parse_block()?;1601 Ok(ConstBlockItem { id: DUMMY_NODE_ID, span: const_span.to(block.span), block })1602 }16031604 /// Parse a static item with the prefix `"static" "mut"?` already parsed and stored in1605 /// `mutability`.1606 ///1607 /// ```ebnf1608 /// Static = "static" "mut"? $ident ":" $ty (= $expr)? ";" ;1609 /// ```1610 fn parse_static_item(1611 &mut self,1612 safety: Safety,1613 mutability: Mutability,1614 ) -> PResult<'a, ItemKind> {1615 let ident = self.parse_ident()?;16161617 if self.token == TokenKind::Lt && self.may_recover() {1618 let generics = self.parse_generics()?;1619 self.dcx().emit_err(errors::StaticWithGenerics { span: generics.span });1620 }16211622 // Parse the type of a static item. That is, the `":" $ty` fragment.1623 // FIXME: This could maybe benefit from `.may_recover()`?1624 let ty = match (self.eat(exp!(Colon)), self.check(exp!(Eq)) | self.check(exp!(Semi))) {1625 (true, false) => self.parse_ty()?,1626 // If there wasn't a `:` or the colon was followed by a `=` or `;`, recover a missing1627 // type.1628 (colon, _) => self.recover_missing_global_item_type(colon, Some(mutability)),1629 };16301631 let expr = if self.eat(exp!(Eq)) { Some(self.parse_expr()?) } else { None };16321633 self.expect_semi()?;16341635 let item = StaticItem {1636 ident,1637 ty,1638 safety,1639 mutability,1640 expr,1641 define_opaque: None,1642 eii_impls: ThinVec::default(),1643 };1644 Ok(ItemKind::Static(Box::new(item)))1645 }16461647 /// Parse a constant item with the prefix `"const"` already parsed.1648 ///1649 /// If `const_arg` is true, any expression assigned to the const will be parsed1650 /// as a const_arg instead of a body expression.1651 ///1652 /// ```ebnf1653 /// Const = "const" ($ident | "_") Generics ":" $ty (= $expr)? WhereClause ";" ;1654 /// ```1655 fn parse_const_item(1656 &mut self,1657 const_arg: bool,1658 const_span: Span,1659 ) -> PResult<'a, (Ident, Generics, Box<Ty>, ConstItemRhsKind)> {1660 let ident = self.parse_ident_or_underscore()?;16611662 let mut generics = self.parse_generics()?;16631664 // Check the span for emptiness instead of the list of parameters in order to correctly1665 // recognize and subsequently flag empty parameter lists (`<>`) as unstable.1666 if !generics.span.is_empty() {1667 self.psess.gated_spans.gate(sym::generic_const_items, generics.span);1668 }16691670 // Parse the type of a constant item. That is, the `":" $ty` fragment.1671 // FIXME: This could maybe benefit from `.may_recover()`?1672 let ty = match (1673 self.eat(exp!(Colon)),1674 self.check(exp!(Eq)) | self.check(exp!(Semi)) | self.check_keyword(exp!(Where)),1675 ) {1676 (true, false) => self.parse_ty()?,1677 // If there wasn't a `:` or the colon was followed by a `=`, `;` or `where`, recover a missing type.1678 (colon, _) => self.recover_missing_global_item_type(colon, None),1679 };16801681 // Proactively parse a where-clause to be able to provide a good error message in case we1682 // encounter the item body following it.1683 let before_where_clause =1684 if self.may_recover() { self.parse_where_clause()? } else { WhereClause::default() };16851686 let rhs = match (self.eat(exp!(Eq)), const_arg) {1687 (true, true) => ConstItemRhsKind::TypeConst {1688 rhs: Some(self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct)?),1689 },1690 (true, false) => ConstItemRhsKind::Body { rhs: Some(self.parse_expr()?) },1691 (false, true) => ConstItemRhsKind::TypeConst { rhs: None },1692 (false, false) => ConstItemRhsKind::Body { rhs: None },1693 };16941695 let after_where_clause = self.parse_where_clause()?;16961697 // Provide a nice error message if the user placed a where-clause before the item body.1698 // Users may be tempted to write such code if they are still used to the deprecated1699 // where-clause location on type aliases and associated types. See also #89122.1700 if before_where_clause.has_where_token1701 && let Some(rhs_span) = rhs.span()1702 {1703 self.dcx().emit_err(errors::WhereClauseBeforeConstBody {1704 span: before_where_clause.span,1705 name: ident.span,1706 body: rhs_span,1707 sugg: if !after_where_clause.has_where_token {1708 self.psess.source_map().span_to_snippet(rhs_span).ok().map(|body_s| {1709 errors::WhereClauseBeforeConstBodySugg {1710 left: before_where_clause.span.shrink_to_lo(),1711 snippet: body_s,1712 right: before_where_clause.span.shrink_to_hi().to(rhs_span),1713 }1714 })1715 } else {1716 // FIXME(generic_const_items): Provide a structured suggestion to merge the first1717 // where-clause into the second one.1718 None1719 },1720 });1721 }17221723 // Merge the predicates of both where-clauses since either one can be relevant.1724 // If we didn't parse a body (which is valid for associated consts in traits) and we were1725 // allowed to recover, `before_where_clause` contains the predicates, otherwise they are1726 // in `after_where_clause`. Further, both of them might contain predicates iff two1727 // where-clauses were provided which is syntactically ill-formed but we want to recover from1728 // it and treat them as one large where-clause.1729 let mut predicates = before_where_clause.predicates;1730 predicates.extend(after_where_clause.predicates);1731 let where_clause = WhereClause {1732 has_where_token: before_where_clause.has_where_token1733 || after_where_clause.has_where_token,1734 predicates,1735 span: if after_where_clause.has_where_token {1736 after_where_clause.span1737 } else {1738 before_where_clause.span1739 },1740 };17411742 if where_clause.has_where_token {1743 self.psess.gated_spans.gate(sym::generic_const_items, where_clause.span);1744 }17451746 generics.where_clause = where_clause;17471748 if let Some(rhs) = self.try_recover_const_missing_semi(&rhs, const_span) {1749 return Ok((ident, generics, ty, ConstItemRhsKind::Body { rhs: Some(rhs) }));1750 }1751 self.expect_semi()?;17521753 Ok((ident, generics, ty, rhs))1754 }17551756 /// We were supposed to parse `":" $ty` but the `:` or the type was missing.1757 /// This means that the type is missing.1758 fn recover_missing_global_item_type(1759 &mut self,1760 colon_present: bool,1761 m: Option<Mutability>,1762 ) -> Box<Ty> {1763 // Construct the error and stash it away with the hope1764 // that typeck will later enrich the error with a type.1765 let kind = match m {1766 Some(Mutability::Mut) => "static mut",1767 Some(Mutability::Not) => "static",1768 None => "const",1769 };17701771 let colon = match colon_present {1772 true => "",1773 false => ":",1774 };17751776 let span = self.prev_token.span.shrink_to_hi();1777 let err = self.dcx().create_err(errors::MissingConstType { span, colon, kind });1778 err.stash(span, StashKey::ItemNoType);17791780 // The user intended that the type be inferred,1781 // so treat this as if the user wrote e.g. `const A: _ = expr;`.1782 Box::new(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID, tokens: None })1783 }17841785 /// Parses an enum declaration.1786 fn parse_item_enum(&mut self) -> PResult<'a, ItemKind> {1787 if self.token.is_keyword(kw::Struct) {1788 let span = self.prev_token.span.to(self.token.span);1789 let err = errors::EnumStructMutuallyExclusive { span };1790 if self.look_ahead(1, |t| t.is_ident()) {1791 self.bump();1792 self.dcx().emit_err(err);1793 } else {1794 return Err(self.dcx().create_err(err));1795 }1796 }17971798 let prev_span = self.prev_token.span;1799 let ident = self.parse_ident()?;1800 let mut generics = self.parse_generics()?;1801 generics.where_clause = self.parse_where_clause()?;18021803 // Possibly recover `enum Foo;` instead of `enum Foo {}`1804 let (variants, _) = if self.token == TokenKind::Semi {1805 self.dcx().emit_err(errors::UseEmptyBlockNotSemi { span: self.token.span });1806 self.bump();1807 (thin_vec![], Trailing::No)1808 } else {1809 self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), |p| {1810 p.parse_enum_variant(ident.span)1811 })1812 .map_err(|mut err| {1813 err.span_label(ident.span, "while parsing this enum");1814 // Try to recover `enum Foo { ident : Ty }`.1815 if self.prev_token.is_non_reserved_ident() && self.token == token::Colon {1816 let snapshot = self.create_snapshot_for_diagnostic();1817 self.bump();1818 match self.parse_ty() {1819 Ok(_) => {1820 err.span_suggestion_verbose(1821 prev_span,1822 "perhaps you meant to use `struct` here",1823 "struct",1824 Applicability::MaybeIncorrect,1825 );1826 }1827 Err(e) => {1828 e.cancel();1829 }1830 }1831 self.restore_snapshot(snapshot);1832 }1833 self.eat_to_tokens(&[exp!(CloseBrace)]);1834 self.bump(); // }1835 err1836 })?1837 };18381839 let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() };1840 Ok(ItemKind::Enum(ident, generics, enum_definition))1841 }18421843 fn parse_enum_variant(&mut self, span: Span) -> PResult<'a, Option<Variant>> {1844 self.recover_vcs_conflict_marker();1845 let variant_attrs = self.parse_outer_attributes()?;1846 self.recover_vcs_conflict_marker();1847 let help = "enum variants can be `Variant`, `Variant = <integer>`, \1848 `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`";1849 self.collect_tokens(None, variant_attrs, ForceCollect::No, |this, variant_attrs| {1850 let vlo = this.token.span;18511852 let vis = this.parse_visibility(FollowedByType::No)?;1853 if !this.recover_nested_adt_item(kw::Enum)? {1854 return Ok((None, Trailing::No, UsePreAttrPos::No));1855 }1856 let ident = this.parse_field_ident("enum", vlo)?;18571858 if this.token == token::Bang {1859 if let Err(err) = this.unexpected() {1860 err.with_note(msg!("macros cannot expand to enum variants")).emit();1861 }18621863 this.bump();1864 this.parse_delim_args()?;18651866 return Ok((None, Trailing::from(this.token == token::Comma), UsePreAttrPos::No));1867 }18681869 let struct_def = if this.check(exp!(OpenBrace)) {1870 // Parse a struct variant.1871 let (fields, recovered) =1872 match this.parse_record_struct_body("struct", ident.span, false) {1873 Ok((fields, recovered)) => (fields, recovered),1874 Err(mut err) => {1875 if this.token == token::Colon {1876 // We handle `enum` to `struct` suggestion in the caller.1877 return Err(err);1878 }1879 this.eat_to_tokens(&[exp!(CloseBrace)]);1880 this.bump(); // }1881 err.span_label(span, "while parsing this enum");1882 err.help(help);1883 let guar = err.emit();1884 (thin_vec![], Recovered::Yes(guar))1885 }1886 };1887 VariantData::Struct { fields, recovered }1888 } else if this.check(exp!(OpenParen)) {1889 let body = match this.parse_tuple_struct_body() {1890 Ok(body) => body,1891 Err(mut err) => {1892 if this.token == token::Colon {1893 // We handle `enum` to `struct` suggestion in the caller.1894 return Err(err);1895 }1896 this.eat_to_tokens(&[exp!(CloseParen)]);1897 this.bump(); // )1898 err.span_label(span, "while parsing this enum");1899 err.help(help);1900 err.emit();1901 thin_vec![]1902 }1903 };1904 VariantData::Tuple(body, DUMMY_NODE_ID)1905 } else {1906 VariantData::Unit(DUMMY_NODE_ID)1907 };19081909 let disr_expr = if this.eat(exp!(Eq)) {1910 Some(this.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?)1911 } else {1912 None1913 };19141915 let vr = ast::Variant {1916 ident,1917 vis,1918 id: DUMMY_NODE_ID,1919 attrs: variant_attrs,1920 data: struct_def,1921 disr_expr,1922 span: vlo.to(this.prev_token.span),1923 is_placeholder: false,1924 };19251926 Ok((Some(vr), Trailing::from(this.token == token::Comma), UsePreAttrPos::No))1927 })1928 .map_err(|mut err| {1929 err.help(help);1930 err1931 })1932 }19331934 /// Parses `struct Foo { ... }`.1935 fn parse_item_struct(&mut self) -> PResult<'a, ItemKind> {1936 let ident = self.parse_ident()?;19371938 let mut generics = self.parse_generics()?;19391940 // There is a special case worth noting here, as reported in issue #17904.1941 // If we are parsing a tuple struct it is the case that the where clause1942 // should follow the field list. Like so:1943 //1944 // struct Foo<T>(T) where T: Copy;1945 //1946 // If we are parsing a normal record-style struct it is the case1947 // that the where clause comes before the body, and after the generics.1948 // So if we look ahead and see a brace or a where-clause we begin1949 // parsing a record style struct.1950 //1951 // Otherwise if we look ahead and see a paren we parse a tuple-style1952 // struct.19531954 let vdata = if self.token.is_keyword(kw::Where) {1955 let tuple_struct_body;1956 (generics.where_clause, tuple_struct_body) =1957 self.parse_struct_where_clause(ident, generics.span)?;19581959 if let Some(body) = tuple_struct_body {1960 // If we see a misplaced tuple struct body: `struct Foo<T> where T: Copy, (T);`1961 let body = VariantData::Tuple(body, DUMMY_NODE_ID);1962 self.expect_semi()?;1963 body1964 } else if self.eat(exp!(Semi)) {1965 // If we see a: `struct Foo<T> where T: Copy;` style decl.1966 VariantData::Unit(DUMMY_NODE_ID)1967 } else {1968 // If we see: `struct Foo<T> where T: Copy { ... }`1969 let (fields, recovered) = self.parse_record_struct_body(1970 "struct",1971 ident.span,1972 generics.where_clause.has_where_token,1973 )?;1974 VariantData::Struct { fields, recovered }1975 }1976 // No `where` so: `struct Foo<T>;`1977 } else if self.eat(exp!(Semi)) {1978 VariantData::Unit(DUMMY_NODE_ID)1979 // Record-style struct definition1980 } else if self.token == token::OpenBrace {1981 let (fields, recovered) = self.parse_record_struct_body(1982 "struct",1983 ident.span,1984 generics.where_clause.has_where_token,1985 )?;1986 VariantData::Struct { fields, recovered }1987 // Tuple-style struct definition with optional where-clause.1988 } else if self.token == token::OpenParen {1989 let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID);1990 generics.where_clause = self.parse_where_clause()?;1991 self.expect_semi()?;1992 body1993 } else {1994 let err = errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token);1995 return Err(self.dcx().create_err(err));1996 };19971998 Ok(ItemKind::Struct(ident, generics, vdata))1999 }
Findings
✓ No findings reported for this file.