compiler/rustc_parse/src/parser/item.rs RUST 3,664 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 3,664.
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.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.