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::{27 self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField,28 UseDoubleColonSuggestion, UseRegularStructSuggestion,29};30use crate::exp;3132impl<'a> Parser<'a> {33 /// Parses a source module as a crate. This is the main entry point for the parser.34 pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {35 let (attrs, items, spans) = self.parse_mod(exp!(Eof))?;36 Ok(ast::Crate { attrs, items, spans, id: DUMMY_NODE_ID, is_placeholder: false })37 }3839 /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.40 fn parse_item_mod(&mut self, attrs: &mut AttrVec) -> PResult<'a, ItemKind> {41 let safety = self.parse_safety(Case::Sensitive);42 self.expect_keyword(exp!(Mod))?;43 let ident = self.parse_ident()?;44 let mod_kind = if self.eat(exp!(Semi)) {45 ModKind::Unloaded46 } else {47 self.expect(exp!(OpenBrace))?;48 let (inner_attrs, items, inner_span) = self.parse_mod(exp!(CloseBrace))?;49 attrs.extend(inner_attrs);50 ModKind::Loaded(items, Inline::Yes, inner_span)51 };52 Ok(ItemKind::Mod(safety, ident, mod_kind))53 }5455 /// Parses the contents of a module (inner attributes followed by module items).56 /// We exit once we hit `term` which can be either57 /// - EOF (for files)58 /// - `}` for mod items59 pub fn parse_mod(60 &mut self,61 term: ExpTokenPair,62 ) -> PResult<'a, (AttrVec, ThinVec<Box<Item>>, ModSpans)> {63 let lo = self.token.span;64 let attrs = self.parse_inner_attributes()?;6566 let post_attr_lo = self.token.span;67 let mut items: ThinVec<Box<_>> = ThinVec::new();6869 // There shouldn't be any stray semicolons before or after items.70 // `parse_item` consumes the appropriate semicolons so any leftover is an error.71 loop {72 while self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {} // Eat all bad semicolons73 let Some(item) = self.parse_item(ForceCollect::No, AllowConstBlockItems::Yes)? else {74 break;75 };76 items.push(item);77 }7879 if !self.eat(term) {80 let token_str = super::token_descr(&self.token);81 if !self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {82 let is_let = self.token.is_keyword(kw::Let);83 let is_let_mut = is_let && self.look_ahead(1, |t| t.is_keyword(kw::Mut));84 let let_has_ident = is_let && !is_let_mut && self.is_kw_followed_by_ident(kw::Let);8586 let msg = format!("expected item, found {token_str}");87 let mut err = self.dcx().struct_span_err(self.token.span, msg);8889 let label = if is_let {90 "`let` cannot be used for global variables"91 } else {92 "expected item"93 };94 err.span_label(self.token.span, label);9596 if is_let {97 if is_let_mut {98 err.help("consider using `static` and a `Mutex` instead of `let mut`");99 } else if let_has_ident {100 err.span_suggestion_short(101 self.token.span,102 "consider using `static` or `const` instead of `let`",103 "static",104 Applicability::MaybeIncorrect,105 );106 } else {107 err.help("consider using `static` or `const` instead of `let`");108 }109 }110 err.note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>");111 return Err(err);112 }113 }114115 let inject_use_span = post_attr_lo.data().with_hi(post_attr_lo.lo());116 let mod_spans = ModSpans { inner_span: lo.to(self.prev_token.span), inject_use_span };117 Ok((attrs, items, mod_spans))118 }119}120121enum ReuseKind {122 Path,123 Impl,124}125126impl<'a> Parser<'a> {127 pub fn parse_item(128 &mut self,129 force_collect: ForceCollect,130 allow_const_block_items: AllowConstBlockItems,131 ) -> PResult<'a, Option<Box<Item>>> {132 let fn_parse_mode =133 FnParseMode { req_name: |_, _| true, context: FnContext::Free, req_body: true };134 self.parse_item_(fn_parse_mode, force_collect, allow_const_block_items)135 .map(|i| i.map(Box::new))136 }137138 fn parse_item_(139 &mut self,140 fn_parse_mode: FnParseMode,141 force_collect: ForceCollect,142 const_block_items_allowed: AllowConstBlockItems,143 ) -> PResult<'a, Option<Item>> {144 self.recover_vcs_conflict_marker();145 let attrs = self.parse_outer_attributes()?;146 self.recover_vcs_conflict_marker();147 self.parse_item_common(148 attrs,149 true,150 false,151 fn_parse_mode,152 force_collect,153 const_block_items_allowed,154 )155 }156157 pub(super) fn parse_item_common(158 &mut self,159 attrs: AttrWrapper,160 mac_allowed: bool,161 attrs_allowed: bool,162 fn_parse_mode: FnParseMode,163 force_collect: ForceCollect,164 allow_const_block_items: AllowConstBlockItems,165 ) -> PResult<'a, Option<Item>> {166 if let Some(item) = self.eat_metavar_seq(MetaVarKind::Item, |this| {167 this.parse_item(ForceCollect::Yes, allow_const_block_items)168 }) {169 let mut item = item.expect("an actual item");170 attrs.prepend_to_nt_inner(&mut item.attrs);171 return Ok(Some(*item));172 }173174 self.collect_tokens(None, attrs, force_collect, |this, mut attrs| {175 let lo = this.token.span;176 let vis = this.parse_visibility(FollowedByType::No)?;177 let mut def = this.parse_defaultness();178 let kind = this.parse_item_kind(179 &mut attrs,180 mac_allowed,181 allow_const_block_items,182 lo,183 &vis,184 &mut def,185 fn_parse_mode,186 Case::Sensitive,187 )?;188 if let Some(kind) = kind {189 this.error_on_unconsumed_default(def, &kind);190 let span = lo.to(this.prev_token.span);191 let id = DUMMY_NODE_ID;192 let item = Item { attrs, id, kind, vis, span, tokens: None };193 return Ok((Some(item), Trailing::No, UsePreAttrPos::No));194 }195196 // At this point, we have failed to parse an item.197 if !matches!(vis.kind, VisibilityKind::Inherited) {198 let vis_str = pprust::vis_to_string(&vis).trim_end().to_string();199 let mut err = this.dcx().create_err(errors::VisibilityNotFollowedByItem {200 span: vis.span,201 vis: vis_str,202 });203 if let Some((ident, _)) = this.token.ident()204 && !ident.is_used_keyword()205 && let Some((similar_kw, is_incorrect_case)) = ident206 .name207 .find_similar(&rustc_span::symbol::used_keywords(|| ident.span.edition()))208 {209 err.subdiagnostic(errors::MisspelledKw {210 similar_kw: similar_kw.to_string(),211 span: ident.span,212 is_incorrect_case,213 });214 }215 err.emit();216 }217218 if let Defaultness::Default(span) = def {219 this.dcx().emit_err(errors::DefaultNotFollowedByItem { span });220 } else if let Defaultness::Final(span) = def {221 this.dcx().emit_err(errors::FinalNotFollowedByItem { span });222 }223224 if !attrs_allowed {225 this.recover_attrs_no_item(&attrs)?;226 }227 Ok((None, Trailing::No, UsePreAttrPos::No))228 })229 }230231 /// Error in-case `default`/`final` was parsed in an in-appropriate context.232 fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {233 match def {234 Defaultness::Default(span) => {235 self.dcx().emit_err(errors::InappropriateDefault {236 span,237 article: kind.article(),238 descr: kind.descr(),239 });240 }241 Defaultness::Final(span) => {242 self.dcx().emit_err(errors::InappropriateFinal {243 span,244 article: kind.article(),245 descr: kind.descr(),246 });247 }248 Defaultness::Implicit => (),249 }250 }251252 /// Parses one of the items allowed by the flags.253 fn parse_item_kind(254 &mut self,255 attrs: &mut AttrVec,256 macros_allowed: bool,257 allow_const_block_items: AllowConstBlockItems,258 lo: Span,259 vis: &Visibility,260 def: &mut Defaultness,261 fn_parse_mode: FnParseMode,262 case: Case,263 ) -> PResult<'a, Option<ItemKind>> {264 let check_pub = def == &Defaultness::Implicit;265 let mut def_ = || mem::replace(def, Defaultness::Implicit);266267 let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) {268 self.parse_use_item()?269 } else if self.check_fn_front_matter(check_pub, case) {270 // FUNCTION ITEM271 let defaultness = def_();272 if let Defaultness::Default(span) = defaultness {273 // Default functions should only require feature `min_specialization`. We remove the274 // `specialization` tag again as such spans *require* feature `specialization` to be275 // enabled. In a later stage, we make `specialization` imply `min_specialization`.276 self.psess.gated_spans.gate(sym::min_specialization, span);277 self.psess.gated_spans.ungate_last(sym::specialization, span);278 }279 let (ident, sig, generics, contract, body) =280 self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?;281 ItemKind::Fn(Box::new(Fn {282 defaultness,283 ident,284 sig,285 generics,286 contract,287 body,288 define_opaque: None,289 eii_impls: ThinVec::new(),290 }))291 } else if self.eat_keyword_case(exp!(Extern), case) {292 if self.eat_keyword_case(exp!(Crate), case) {293 // EXTERN CRATE294 self.parse_item_extern_crate()?295 } else {296 // EXTERN BLOCK297 self.parse_item_foreign_mod(attrs, Safety::Default)?298 }299 } else if self.is_unsafe_foreign_mod() {300 // EXTERN BLOCK301 let safety = self.parse_safety(Case::Sensitive);302 self.expect_keyword(exp!(Extern))?;303 self.parse_item_foreign_mod(attrs, safety)?304 } else if let Some(safety) = self.parse_global_static_front_matter(case) {305 // STATIC ITEM306 let mutability = self.parse_mutability();307 self.parse_static_item(safety, mutability)?308 } else if self.check_keyword_case(exp!(Trait), case) || self.check_trait_front_matter() {309 // TRAIT ITEM310 self.parse_item_trait(attrs, lo)?311 } else if self.check_impl_frontmatter(0) {312 // IMPL ITEM313 self.parse_item_impl(attrs, def_(), false)?314 } else if let AllowConstBlockItems::Yes | AllowConstBlockItems::DoesNotMatter =315 allow_const_block_items316 && self.check_inline_const(0)317 {318 // CONST BLOCK ITEM319 if let AllowConstBlockItems::DoesNotMatter = allow_const_block_items {320 debug!("Parsing a const block item that does not matter: {:?}", self.token.span);321 };322 ItemKind::ConstBlock(self.parse_const_block_item()?)323 } else if let Const::Yes(const_span) = self.parse_constness(case) {324 // CONST ITEM325 self.recover_const_mut(const_span);326 self.recover_missing_kw_before_item()?;327 let (ident, generics, ty, rhs_kind) = self.parse_const_item(false, const_span)?;328 ItemKind::Const(Box::new(ConstItem {329 defaultness: def_(),330 ident,331 generics,332 ty,333 rhs_kind,334 define_opaque: None,335 }))336 } else if let Some(kind) = self.is_reuse_item() {337 self.parse_item_delegation(attrs, def_(), kind)?338 } else if self.check_keyword_case(exp!(Mod), case)339 || self.check_keyword_case(exp!(Unsafe), case) && self.is_keyword_ahead(1, &[kw::Mod])340 {341 // MODULE ITEM342 self.parse_item_mod(attrs)?343 } else if self.eat_keyword_case(exp!(Type), case) {344 if let Const::Yes(const_span) = self.parse_constness(case) {345 // TYPE CONST (mgca)346 self.recover_const_mut(const_span);347 self.recover_missing_kw_before_item()?;348 let (ident, generics, ty, rhs_kind) = self.parse_const_item(true, const_span)?;349 // Make sure this is only allowed if the feature gate is enabled.350 // #![feature(mgca_type_const_syntax)]351 self.psess.gated_spans.gate(sym::mgca_type_const_syntax, lo.to(const_span));352 ItemKind::Const(Box::new(ConstItem {353 defaultness: def_(),354 ident,355 generics,356 ty,357 rhs_kind,358 define_opaque: None,359 }))360 } else {361 // TYPE ITEM362 self.parse_type_alias(def_())?363 }364 } else if self.eat_keyword_case(exp!(Enum), case) {365 // ENUM ITEM366 self.parse_item_enum()?367 } else if self.eat_keyword_case(exp!(Struct), case) {368 // STRUCT ITEM369 self.parse_item_struct()?370 } else if self.is_kw_followed_by_ident(kw::Union) {371 // UNION ITEM372 self.bump(); // `union`373 self.parse_item_union()?374 } else if self.is_builtin() {375 // BUILTIN# ITEM376 return self.parse_item_builtin();377 } else if self.eat_keyword_case(exp!(Macro), case) {378 // MACROS 2.0 ITEM379 self.parse_item_decl_macro(lo)?380 } else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {381 // MACRO_RULES ITEM382 self.parse_item_macro_rules(vis, has_bang)?383 } else if self.isnt_macro_invocation()384 && (self.token.is_ident_named(sym::import)385 || self.token.is_ident_named(sym::using)386 || self.token.is_ident_named(sym::include)387 || self.token.is_ident_named(sym::require))388 {389 return self.recover_import_as_use();390 } else if self.isnt_macro_invocation() && vis.kind.is_pub() {391 self.recover_missing_kw_before_item()?;392 return Ok(None);393 } else if self.isnt_macro_invocation() && case == Case::Sensitive {394 _ = def_;395396 // Recover wrong cased keywords397 return self.parse_item_kind(398 attrs,399 macros_allowed,400 allow_const_block_items,401 lo,402 vis,403 def,404 fn_parse_mode,405 Case::Insensitive,406 );407 } else if macros_allowed && self.check_path() {408 if self.isnt_macro_invocation() {409 self.recover_missing_kw_before_item()?;410 }411 // MACRO INVOCATION ITEM412 ItemKind::MacCall(Box::new(self.parse_item_macro(vis)?))413 } else {414 return Ok(None);415 };416 Ok(Some(info))417 }418419 fn recover_import_as_use(&mut self) -> PResult<'a, Option<ItemKind>> {420 let span = self.token.span;421 let token_name = super::token_descr(&self.token);422 let snapshot = self.create_snapshot_for_diagnostic();423 self.bump();424 match self.parse_use_item() {425 Ok(u) => {426 self.dcx().emit_err(errors::RecoverImportAsUse { span, token_name });427 Ok(Some(u))428 }429 Err(e) => {430 e.cancel();431 self.restore_snapshot(snapshot);432 Ok(None)433 }434 }435 }436437 fn parse_use_item(&mut self) -> PResult<'a, ItemKind> {438 let tree = self.parse_use_tree()?;439 if let Err(mut e) = self.expect_semi() {440 match tree.kind {441 UseTreeKind::Glob(_) => {442 e.note("the wildcard token must be last on the path");443 }444 UseTreeKind::Nested { .. } => {445 e.note("glob-like brace syntax must be last on the path");446 }447 _ => (),448 }449 return Err(e);450 }451 Ok(ItemKind::Use(tree))452 }453454 /// When parsing a statement, would the start of a path be an item?455 pub(super) fn is_path_start_item(&mut self) -> bool {456 self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`457 || self.is_reuse_item().is_some() // yes: `reuse impl Trait for Struct { self.0 }`, yes: `reuse some_path::foo;`458 || self.check_trait_front_matter() // no: `auto::b`, yes: `auto trait X { .. }`459 || self.is_async_fn() // no(2015): `async::b`, yes: `async fn`460 || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac`461 }462463 fn is_reuse_item(&mut self) -> Option<ReuseKind> {464 if !self.token.is_keyword(kw::Reuse) {465 return None;466 }467468 // no: `reuse ::path` for compatibility reasons with macro invocations469 if self.look_ahead(1, |t| t.is_path_start() && *t != token::PathSep) {470 Some(ReuseKind::Path)471 } else if self.check_impl_frontmatter(1) {472 Some(ReuseKind::Impl)473 } else {474 None475 }476 }477478 /// Are we sure this could not possibly be a macro invocation?479 fn isnt_macro_invocation(&mut self) -> bool {480 self.check_ident() && self.look_ahead(1, |t| *t != token::Bang && *t != token::PathSep)481 }482483 /// Recover on encountering a struct, enum, or method definition where the user484 /// forgot to add the `struct`, `enum`, or `fn` keyword485 fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> {486 let is_pub = self.prev_token.is_keyword(kw::Pub);487 let is_const = self.prev_token.is_keyword(kw::Const);488 let ident_span = self.token.span;489 let span = if is_pub { self.prev_token.span.to(ident_span) } else { ident_span };490 let insert_span = ident_span.shrink_to_lo();491492 let ident = if self.token.is_ident()493 && (!is_const || self.look_ahead(1, |t| *t == token::OpenParen))494 && self.look_ahead(1, |t| {495 matches!(t.kind, token::Lt | token::OpenBrace | token::OpenParen)496 }) {497 self.parse_ident_common(true).unwrap()498 } else {499 return Ok(());500 };501502 let mut found_generics = false;503 if self.check(exp!(Lt)) {504 found_generics = true;505 self.eat_to_tokens(&[exp!(Gt)]);506 self.bump(); // `>`507 }508509 let err = if self.check(exp!(OpenBrace)) {510 // possible struct or enum definition where `struct` or `enum` was forgotten511 if self.look_ahead(1, |t| *t == token::CloseBrace) {512 // `S {}` could be unit enum or struct513 Some(errors::MissingKeywordForItemDefinition::EnumOrStruct { span })514 } else if self.look_ahead(2, |t| *t == token::Colon)515 || self.look_ahead(3, |t| *t == token::Colon)516 {517 // `S { f:` or `S { pub f:`518 Some(errors::MissingKeywordForItemDefinition::Struct { span, insert_span, ident })519 } else {520 Some(errors::MissingKeywordForItemDefinition::Enum { span, insert_span, ident })521 }522 } else if self.check(exp!(OpenParen)) {523 // possible function or tuple struct definition where `fn` or `struct` was forgotten524 self.bump(); // `(`525 let is_method = self.recover_self_param();526527 self.consume_block(exp!(OpenParen), exp!(CloseParen), ConsumeClosingDelim::Yes);528529 let err = if self.check(exp!(RArrow)) || self.check(exp!(OpenBrace)) {530 self.eat_to_tokens(&[exp!(OpenBrace)]);531 self.bump(); // `{`532 self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);533 if is_method {534 errors::MissingKeywordForItemDefinition::Method { span, insert_span, ident }535 } else {536 errors::MissingKeywordForItemDefinition::Function { span, insert_span, ident }537 }538 } else if is_pub && self.check(exp!(Semi)) {539 errors::MissingKeywordForItemDefinition::Struct { span, insert_span, ident }540 } else {541 errors::MissingKeywordForItemDefinition::Ambiguous {542 span,543 subdiag: if found_generics {544 None545 } else if let Ok(snippet) = self.span_to_snippet(ident_span) {546 Some(errors::AmbiguousMissingKwForItemSub::SuggestMacro {547 span: ident_span,548 snippet,549 })550 } else {551 Some(errors::AmbiguousMissingKwForItemSub::HelpMacro)552 },553 }554 };555 Some(err)556 } else if found_generics {557 Some(errors::MissingKeywordForItemDefinition::Ambiguous { span, subdiag: None })558 } else {559 None560 };561562 if let Some(err) = err { Err(self.dcx().create_err(err)) } else { Ok(()) }563 }564565 fn parse_item_builtin(&mut self) -> PResult<'a, Option<ItemKind>> {566 // To be expanded567 Ok(None)568 }569570 /// Parses an item macro, e.g., `item!();`.571 fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> {572 let path = self.parse_path(PathStyle::Mod)?; // `foo::bar`573 self.expect(exp!(Bang))?; // `!`574 match self.parse_delim_args() {575 // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`.576 Ok(args) => {577 self.eat_semi_for_macro_if_needed(&args, Some(&path));578 self.complain_if_pub_macro(vis, false);579 Ok(MacCall { path, args })580 }581582 Err(mut err) => {583 // Maybe the user misspelled `macro_rules` (issue #91227)584 if self.token.is_ident()585 && let [segment] = path.segments.as_slice()586 && edit_distance("macro_rules", &segment.ident.to_string(), 2).is_some()587 {588 err.span_suggestion(589 path.span,590 "perhaps you meant to define a macro",591 "macro_rules",592 Applicability::MachineApplicable,593 );594 }595 Err(err)596 }597 }598 }599600 /// Recover if we parsed attributes and expected an item but there was none.601 fn recover_attrs_no_item(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> {602 let ([start @ end] | [start, .., end]) = attrs else {603 return Ok(());604 };605 let msg = if end.is_doc_comment() {606 "expected item after doc comment"607 } else {608 "expected item after attributes"609 };610 let mut err = self.dcx().struct_span_err(end.span, msg);611 if end.is_doc_comment() {612 err.span_label(end.span, "this doc comment doesn't document anything");613 } else if self.token == TokenKind::Semi {614 err.span_suggestion_verbose(615 self.token.span,616 "consider removing this semicolon",617 "",618 Applicability::MaybeIncorrect,619 );620 }621 if let [.., penultimate, _] = attrs {622 err.span_label(start.span.to(penultimate.span), "other attributes here");623 }624 Err(err)625 }626627 fn is_async_fn(&self) -> bool {628 self.token.is_keyword(kw::Async) && self.is_keyword_ahead(1, &[kw::Fn])629 }630631 fn parse_polarity(&mut self) -> ast::ImplPolarity {632 // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.633 if self.check(exp!(Bang)) && self.look_ahead(1, |t| t.can_begin_type()) {634 self.psess.gated_spans.gate(sym::negative_impls, self.token.span);635 self.bump(); // `!`636 ast::ImplPolarity::Negative(self.prev_token.span)637 } else {638 ast::ImplPolarity::Positive639 }640 }641642 /// Parses an implementation item.643 ///644 /// ```ignore (illustrative)645 /// impl<'a, T> TYPE { /* impl items */ }646 /// impl<'a, T> TRAIT for TYPE { /* impl items */ }647 /// impl<'a, T> !TRAIT for TYPE { /* impl items */ }648 /// impl<'a, T> const TRAIT for TYPE { /* impl items */ }649 /// ```650 ///651 /// We actually parse slightly more relaxed grammar for better error reporting and recovery.652 /// ```ebnf653 /// "impl" GENERICS "const"? "!"? TYPE "for"? (TYPE | "..") ("where" PREDICATES)? "{" BODY "}"654 /// "impl" GENERICS "const"? "!"? TYPE ("where" PREDICATES)? "{" BODY "}"655 /// ```656 fn parse_item_impl(657 &mut self,658 attrs: &mut AttrVec,659 defaultness: Defaultness,660 is_reuse: bool,661 ) -> PResult<'a, ItemKind> {662 let constness = self.parse_constness(Case::Sensitive);663 let safety = self.parse_safety(Case::Sensitive);664 self.expect_keyword(exp!(Impl))?;665666 // First, parse generic parameters if necessary.667 let mut generics = if self.choose_generics_over_qpath(0) {668 self.parse_generics()?669 } else {670 let mut generics = Generics::default();671 // impl A for B {}672 // /\ this is where `generics.span` should point when there are no type params.673 generics.span = self.prev_token.span.shrink_to_hi();674 generics675 };676677 if let Const::Yes(span) = constness {678 self.psess.gated_spans.gate(sym::const_trait_impl, span);679 }680681 // Parse stray `impl async Trait`682 if (self.token_uninterpolated_span().at_least_rust_2018()683 && self.token.is_keyword(kw::Async))684 || self.is_kw_followed_by_ident(kw::Async)685 {686 self.bump();687 self.dcx().emit_err(errors::AsyncImpl { span: self.prev_token.span });688 }689690 let polarity = self.parse_polarity();691692 // Parse both types and traits as a type, then reinterpret if necessary.693 let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt)694 {695 let span = self.prev_token.span.between(self.token.span);696 return Err(self.dcx().create_err(errors::MissingTraitInTraitImpl {697 span,698 for_span: span.to(self.token.span),699 }));700 } else {701 self.parse_ty_with_generics_recovery(&generics)?702 };703704 // If `for` is missing we try to recover.705 let has_for = self.eat_keyword(exp!(For));706 let missing_for_span = self.prev_token.span.between(self.token.span);707708 let ty_second = if self.token == token::DotDot {709 // We need to report this error after `cfg` expansion for compatibility reasons710 self.bump(); // `..`, do not add it to expected tokens711712 // AST validation later detects this `TyKind::Dummy` and emits an713 // error. (#121072 will hopefully remove all this special handling714 // of the obsolete `impl Trait for ..` and then this can go away.)715 Some(self.mk_ty(self.prev_token.span, TyKind::Dummy))716 } else if has_for || self.token.can_begin_type() {717 Some(self.parse_ty()?)718 } else {719 None720 };721722 generics.where_clause = self.parse_where_clause()?;723724 let impl_items = if is_reuse {725 Default::default()726 } else {727 self.parse_item_list(attrs, |p| p.parse_impl_item(ForceCollect::No))?728 };729730 let (of_trait, self_ty) = match ty_second {731 Some(ty_second) => {732 // impl Trait for Type733 if !has_for {734 self.dcx().emit_err(errors::MissingForInTraitImpl { span: missing_for_span });735 }736737 let ty_first = *ty_first;738 let path = match ty_first.kind {739 // This notably includes paths passed through `ty` macro fragments (#46438).740 TyKind::Path(None, path) => path,741 other => {742 if let TyKind::ImplTrait(_, bounds) = other743 && let [bound] = bounds.as_slice()744 && let GenericBound::Trait(poly_trait_ref) = bound745 {746 // Suggest removing extra `impl` keyword:747 // `impl<T: Default> impl Default for Wrapper<T>`748 // ^^^^^749 let extra_impl_kw = ty_first.span.until(bound.span());750 self.dcx().emit_err(errors::ExtraImplKeywordInTraitImpl {751 extra_impl_kw,752 impl_trait_span: ty_first.span,753 });754 poly_trait_ref.trait_ref.path.clone()755 } else {756 return Err(self.dcx().create_err(757 errors::ExpectedTraitInTraitImplFoundType { span: ty_first.span },758 ));759 }760 }761 };762 let trait_ref = TraitRef { path, ref_id: ty_first.id };763764 let of_trait =765 Some(Box::new(TraitImplHeader { defaultness, safety, polarity, trait_ref }));766 (of_trait, ty_second)767 }768 None => {769 let self_ty = ty_first;770 let error = |modifier, modifier_name, modifier_span| {771 self.dcx().create_err(errors::TraitImplModifierInInherentImpl {772 span: self_ty.span,773 modifier,774 modifier_name,775 modifier_span,776 self_ty: self_ty.span,777 })778 };779780 if let Safety::Unsafe(span) = safety {781 error("unsafe", "unsafe", span).with_code(E0197).emit();782 }783 if let ImplPolarity::Negative(span) = polarity {784 error("!", "negative", span).emit();785 }786 if let Defaultness::Default(def_span) = defaultness {787 error("default", "default", def_span).emit();788 }789 if let Const::Yes(span) = constness {790 self.psess.gated_spans.gate(sym::const_trait_impl, span);791 }792 (None, self_ty)793 }794 };795796 Ok(ItemKind::Impl(Impl { generics, of_trait, self_ty, items: impl_items, constness }))797 }798799 fn parse_item_delegation(800 &mut self,801 attrs: &mut AttrVec,802 defaultness: Defaultness,803 kind: ReuseKind,804 ) -> PResult<'a, ItemKind> {805 let span = self.token.span;806 self.expect_keyword(exp!(Reuse))?;807808 let item_kind = match kind {809 ReuseKind::Path => self.parse_path_like_delegation(),810 ReuseKind::Impl => self.parse_impl_delegation(span, attrs, defaultness),811 }?;812813 self.psess.gated_spans.gate(sym::fn_delegation, span.to(self.prev_token.span));814815 Ok(item_kind)816 }817818 fn parse_delegation_body(&mut self) -> PResult<'a, Option<Box<Block>>> {819 Ok(if self.check(exp!(OpenBrace)) {820 Some(self.parse_block()?)821 } else {822 self.expect(exp!(Semi))?;823 None824 })825 }826827 fn parse_impl_delegation(828 &mut self,829 span: Span,830 attrs: &mut AttrVec,831 defaultness: Defaultness,832 ) -> PResult<'a, ItemKind> {833 let mut impl_item = self.parse_item_impl(attrs, defaultness, true)?;834 let ItemKind::Impl(Impl { items, of_trait, .. }) = &mut impl_item else { unreachable!() };835836 let until_expr_span = span.to(self.prev_token.span);837838 let Some(of_trait) = of_trait else {839 return Err(self840 .dcx()841 .create_err(errors::ImplReuseInherentImpl { span: until_expr_span }));842 };843844 let body = self.parse_delegation_body()?;845 let whole_reuse_span = span.to(self.prev_token.span);846847 items.push(Box::new(AssocItem {848 id: DUMMY_NODE_ID,849 attrs: Default::default(),850 span: whole_reuse_span,851 tokens: None,852 vis: Visibility {853 kind: VisibilityKind::Inherited,854 span: whole_reuse_span,855 tokens: None,856 },857 kind: AssocItemKind::DelegationMac(Box::new(DelegationMac {858 qself: None,859 prefix: of_trait.trait_ref.path.clone(),860 suffixes: DelegationSuffixes::Glob(whole_reuse_span),861 body,862 })),863 }));864865 Ok(impl_item)866 }867868 fn parse_path_like_delegation(&mut self) -> PResult<'a, ItemKind> {869 let (qself, path) = if self.eat_lt() {870 let (qself, path) = self.parse_qpath(PathStyle::Expr)?;871 (Some(qself), path)872 } else {873 (None, self.parse_path(PathStyle::Expr)?)874 };875876 let rename = |this: &mut Self| {877 Ok(if this.eat_keyword(exp!(As)) { Some(this.parse_ident()?) } else { None })878 };879880 Ok(if self.eat_path_sep() {881 let suffixes = if self.eat(exp!(Star)) {882 DelegationSuffixes::Glob(self.prev_token.span)883 } else {884 let parse_suffix = |p: &mut Self| Ok((p.parse_path_segment_ident()?, rename(p)?));885 DelegationSuffixes::List(886 self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), parse_suffix)?.0,887 )888 };889890 ItemKind::DelegationMac(Box::new(DelegationMac {891 qself,892 prefix: path,893 suffixes,894 body: self.parse_delegation_body()?,895 }))896 } else {897 let rename = rename(self)?;898 let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);899900 ItemKind::Delegation(Box::new(Delegation {901 id: DUMMY_NODE_ID,902 qself,903 path,904 ident,905 rename,906 body: self.parse_delegation_body()?,907 source: DelegationSource::Single,908 }))909 })910 }911912 fn parse_item_list<T>(913 &mut self,914 attrs: &mut AttrVec,915 mut parse_item: impl FnMut(&mut Parser<'a>) -> PResult<'a, Option<Option<T>>>,916 ) -> PResult<'a, ThinVec<T>> {917 let open_brace_span = self.token.span;918919 // Recover `impl Ty;` instead of `impl Ty {}`920 if self.token == TokenKind::Semi {921 self.dcx().emit_err(errors::UseEmptyBlockNotSemi { span: self.token.span });922 self.bump();923 return Ok(ThinVec::new());924 }925926 self.expect(exp!(OpenBrace))?;927 attrs.extend(self.parse_inner_attributes()?);928929 let mut items = ThinVec::new();930 while !self.eat(exp!(CloseBrace)) {931 if self.recover_doc_comment_before_brace() {932 continue;933 }934 self.recover_vcs_conflict_marker();935 match parse_item(self) {936 Ok(None) => {937 let mut is_unnecessary_semicolon = !items.is_empty()938 // When the close delim is `)` in a case like the following, `token.kind`939 // is expected to be `token::CloseParen`, but the actual `token.kind` is940 // `token::CloseBrace`. This is because the `token.kind` of the close delim941 // is treated as the same as that of the open delim in942 // `TokenTreesReader::parse_token_tree`, even if the delimiters of them are943 // different. Therefore, `token.kind` should not be compared here.944 //945 // issue-60075.rs946 // ```947 // trait T {948 // fn qux() -> Option<usize> {949 // let _ = if true {950 // });951 // ^ this close delim952 // Some(4)953 // }954 // ```955 && self956 .span_to_snippet(self.prev_token.span)957 .is_ok_and(|snippet| snippet == "}")958 && self.token == token::Semi;959 let mut semicolon_span = self.token.span;960 if !is_unnecessary_semicolon {961 // #105369, Detect spurious `;` before assoc fn body962 is_unnecessary_semicolon =963 self.token == token::OpenBrace && self.prev_token == token::Semi;964 semicolon_span = self.prev_token.span;965 }966 // We have to bail or we'll potentially never make progress.967 let non_item_span = self.token.span;968 let is_let = self.token.is_keyword(kw::Let);969970 let mut err =971 self.dcx().struct_span_err(non_item_span, "non-item in item list");972 self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);973 if is_let {974 err.span_suggestion_verbose(975 non_item_span,976 "consider using `const` instead of `let` for associated const",977 "const",978 Applicability::MachineApplicable,979 );980 } else {981 err.span_label(open_brace_span, "item list starts here")982 .span_label(non_item_span, "non-item starts here")983 .span_label(self.prev_token.span, "item list ends here");984 }985 if is_unnecessary_semicolon {986 err.span_suggestion(987 semicolon_span,988 "consider removing this semicolon",989 "",990 Applicability::MaybeIncorrect,991 );992 }993 err.emit();994 break;995 }996 Ok(Some(item)) => items.extend(item),997 Err(err) => {998 self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);999 err.with_span_label(1000 open_brace_span,1001 "while parsing this item list starting here",1002 )1003 .with_span_label(self.prev_token.span, "the item list ends here")1004 .emit();1005 break;1006 }1007 }1008 }1009 Ok(items)1010 }10111012 /// Recover on a doc comment before `}`.1013 fn recover_doc_comment_before_brace(&mut self) -> bool {1014 if let token::DocComment(..) = self.token.kind {1015 if self.look_ahead(1, |tok| tok == &token::CloseBrace) {1016 // FIXME: merge with `DocCommentDoesNotDocumentAnything` (E0585)1017 struct_span_code_err!(1018 self.dcx(),1019 self.token.span,1020 E0584,1021 "found a documentation comment that doesn't document anything",1022 )1023 .with_span_label(self.token.span, "this doc comment doesn't document anything")1024 .with_help(1025 "doc comments must come before what they document, if a comment was \1026 intended use `//`",1027 )1028 .emit();1029 self.bump();1030 return true;1031 }1032 }1033 false1034 }10351036 /// Parses defaultness (i.e., `default` or nothing).1037 fn parse_defaultness(&mut self) -> Defaultness {1038 // We are interested in `default` followed by another identifier.1039 // However, we must avoid keywords that occur as binary operators.1040 // Currently, the only applicable keyword is `as` (`default as Ty`).1041 if self.check_keyword(exp!(Default))1042 && self.look_ahead(1, |t| t.is_non_raw_ident_where(|i| i.name != kw::As))1043 {1044 self.psess.gated_spans.gate(sym::specialization, self.token.span);1045 self.bump(); // `default`1046 Defaultness::Default(self.prev_token_uninterpolated_span())1047 } else if self.eat_keyword(exp!(Final)) {1048 self.psess.gated_spans.gate(sym::final_associated_functions, self.prev_token.span);1049 Defaultness::Final(self.prev_token_uninterpolated_span())1050 } else {1051 Defaultness::Implicit1052 }1053 }10541055 /// Is this an `[impl(in? path)]? const? unsafe? auto? trait` item?1056 fn check_trait_front_matter(&mut self) -> bool {1057 const SUFFIXES: &[&[Symbol]] = &[1058 &[kw::Trait],1059 &[kw::Auto, kw::Trait],1060 &[kw::Unsafe, kw::Trait],1061 &[kw::Unsafe, kw::Auto, kw::Trait],1062 &[kw::Const, kw::Trait],1063 &[kw::Const, kw::Auto, kw::Trait],1064 &[kw::Const, kw::Unsafe, kw::Trait],1065 &[kw::Const, kw::Unsafe, kw::Auto, kw::Trait],1066 ];1067 // `impl(`1068 if self.check_keyword(exp!(Impl)) && self.look_ahead(1, |t| t == &token::OpenParen) {1069 // `impl(in` unambiguously introduces an `impl` restriction1070 if self.is_keyword_ahead(2, &[kw::In]) {1071 return true;1072 }1073 // `impl(crate | self | super)` + SUFFIX1074 if self.is_keyword_ahead(2, &[kw::Crate, kw::SelfLower, kw::Super])1075 && self.look_ahead(3, |t| t == &token::CloseParen)1076 && SUFFIXES.iter().any(|suffix| {1077 suffix.iter().enumerate().all(|(i, kw)| self.is_keyword_ahead(i + 4, &[*kw]))1078 })1079 {1080 return true;1081 }1082 // Recover cases like `impl(path::to::module)` + SUFFIX to suggest inserting `in`.1083 SUFFIXES.iter().any(|suffix| {1084 suffix.iter().enumerate().all(|(i, kw)| {1085 self.tree_look_ahead(i + 2, |t| {1086 if let TokenTree::Token(token, _) = t {1087 token.is_keyword(*kw)1088 } else {1089 false1090 }1091 })1092 .unwrap_or(false)1093 })1094 })1095 } else {1096 SUFFIXES.iter().any(|suffix| {1097 suffix.iter().enumerate().all(|(i, kw)| {1098 // We use `check_keyword` for the first token to include it in the expected tokens.1099 if i == 0 {1100 match *kw {1101 kw::Const => self.check_keyword(exp!(Const)),1102 kw::Unsafe => self.check_keyword(exp!(Unsafe)),1103 kw::Auto => self.check_keyword(exp!(Auto)),1104 kw::Trait => self.check_keyword(exp!(Trait)),1105 _ => unreachable!(),1106 }1107 } else {1108 self.is_keyword_ahead(i, &[*kw])1109 }1110 })1111 })1112 }1113 }11141115 /// Parses `[impl(in? path)]? const? unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`.1116 fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemKind> {1117 let impl_restriction = self.parse_impl_restriction()?;1118 let constness = self.parse_constness(Case::Sensitive);1119 if let Const::Yes(span) = constness {1120 self.psess.gated_spans.gate(sym::const_trait_impl, span);1121 }1122 let safety = self.parse_safety(Case::Sensitive);1123 // Parse optional `auto` prefix.1124 let is_auto = if self.eat_keyword(exp!(Auto)) {1125 self.psess.gated_spans.gate(sym::auto_traits, self.prev_token.span);1126 IsAuto::Yes1127 } else {1128 IsAuto::No1129 };11301131 self.expect_keyword(exp!(Trait))?;1132 let ident = self.parse_ident()?;1133 let mut generics = self.parse_generics()?;11341135 // Parse optional colon and supertrait bounds.1136 let had_colon = self.eat(exp!(Colon));1137 let span_at_colon = self.prev_token.span;1138 let bounds = if had_colon { self.parse_generic_bounds()? } else { Vec::new() };11391140 let span_before_eq = self.prev_token.span;1141 if self.eat(exp!(Eq)) {1142 // It's a trait alias.1143 if had_colon {1144 let span = span_at_colon.to(span_before_eq);1145 self.dcx().emit_err(errors::BoundsNotAllowedOnTraitAliases { span });1146 }11471148 let bounds = self.parse_generic_bounds()?;1149 generics.where_clause = self.parse_where_clause()?;1150 self.expect_semi()?;11511152 let whole_span = lo.to(self.prev_token.span);1153 if is_auto == IsAuto::Yes {1154 self.dcx().emit_err(errors::TraitAliasCannotBeAuto { span: whole_span });1155 }1156 if let Safety::Unsafe(_) = safety {1157 self.dcx().emit_err(errors::TraitAliasCannotBeUnsafe { span: whole_span });1158 }1159 if let RestrictionKind::Restricted { .. } = impl_restriction.kind {1160 self.dcx().emit_err(errors::TraitAliasCannotBeImplRestricted { span: whole_span });1161 }11621163 self.psess.gated_spans.gate(sym::trait_alias, whole_span);11641165 Ok(ItemKind::TraitAlias(Box::new(TraitAlias { constness, ident, generics, bounds })))1166 } else {1167 // It's a normal trait.1168 generics.where_clause = self.parse_where_clause()?;1169 let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?;1170 Ok(ItemKind::Trait(Box::new(Trait {1171 impl_restriction,1172 constness,1173 is_auto,1174 safety,1175 ident,1176 generics,1177 bounds,1178 items,1179 })))1180 }1181 }11821183 pub fn parse_impl_item(1184 &mut self,1185 force_collect: ForceCollect,1186 ) -> PResult<'a, Option<Option<Box<AssocItem>>>> {1187 let fn_parse_mode =1188 FnParseMode { req_name: |_, _| true, context: FnContext::Impl, req_body: true };1189 self.parse_assoc_item(fn_parse_mode, force_collect)1190 }11911192 pub fn parse_trait_item(1193 &mut self,1194 force_collect: ForceCollect,1195 ) -> PResult<'a, Option<Option<Box<AssocItem>>>> {1196 let fn_parse_mode = FnParseMode {1197 req_name: |edition, _| edition >= Edition::Edition2018,1198 context: FnContext::Trait,1199 req_body: false,1200 };1201 self.parse_assoc_item(fn_parse_mode, force_collect)1202 }12031204 /// Parses associated items.1205 fn parse_assoc_item(1206 &mut self,1207 fn_parse_mode: FnParseMode,1208 force_collect: ForceCollect,1209 ) -> PResult<'a, Option<Option<Box<AssocItem>>>> {1210 Ok(self1211 .parse_item_(1212 fn_parse_mode,1213 force_collect,1214 AllowConstBlockItems::DoesNotMatter, // due to `AssocItemKind::try_from` below1215 )?1216 .map(|Item { attrs, id, span, vis, kind, tokens }| {1217 let kind = match AssocItemKind::try_from(kind) {1218 Ok(kind) => kind,1219 Err(kind) => match kind {1220 ItemKind::Static(StaticItem {1221 ident,1222 ty,1223 safety: _,1224 mutability: _,1225 expr,1226 define_opaque,1227 eii_impls: _,1228 }) => {1229 self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span });1230 AssocItemKind::Const(Box::new(ConstItem {1231 defaultness: Defaultness::Implicit,1232 ident,1233 generics: Generics::default(),1234 ty,1235 rhs_kind: ConstItemRhsKind::Body { rhs: expr },1236 define_opaque,1237 }))1238 }1239 _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"),1240 },1241 };1242 Some(Box::new(Item { attrs, id, span, vis, kind, tokens }))1243 }))1244 }12451246 /// Parses a `type` alias with the following grammar:1247 /// ```ebnf1248 /// TypeAlias = "type" Ident Generics (":" GenericBounds)? WhereClause ("=" Ty)? WhereClause ";" ;1249 /// ```1250 /// The `"type"` has already been eaten.1251 fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemKind> {1252 let ident = self.parse_ident()?;1253 let mut generics = self.parse_generics()?;12541255 // Parse optional colon and param bounds.1256 let bounds = if self.eat(exp!(Colon)) { self.parse_generic_bounds()? } else { Vec::new() };1257 generics.where_clause = self.parse_where_clause()?;12581259 let ty = if self.eat(exp!(Eq)) { Some(self.parse_ty()?) } else { None };12601261 let after_where_clause = self.parse_where_clause()?;12621263 self.expect_semi()?;12641265 Ok(ItemKind::TyAlias(Box::new(TyAlias {1266 defaultness,1267 ident,1268 generics,1269 after_where_clause,1270 bounds,1271 ty,1272 })))1273 }12741275 /// Parses a `UseTree`.1276 ///1277 /// ```text1278 /// USE_TREE = [`::`] `*` |1279 /// [`::`] `{` USE_TREE_LIST `}` |1280 /// PATH `::` `*` |1281 /// PATH `::` `{` USE_TREE_LIST `}` |1282 /// PATH [`as` IDENT]1283 /// ```1284 fn parse_use_tree(&mut self) -> PResult<'a, UseTree> {1285 let lo = self.token.span;12861287 let mut prefix =1288 ast::Path { segments: ThinVec::new(), span: lo.shrink_to_lo(), tokens: None };1289 let kind =1290 if self.check(exp!(OpenBrace)) || self.check(exp!(Star)) || self.is_import_coupler() {1291 // `use *;` or `use ::*;` or `use {...};` or `use ::{...};`1292 let mod_sep_ctxt = self.token.span.ctxt();1293 if self.eat_path_sep() {1294 prefix1295 .segments1296 .push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));1297 }12981299 self.parse_use_tree_glob_or_nested()?1300 } else {1301 // `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;`1302 prefix = self.parse_path(PathStyle::Mod)?;13031304 if self.eat_path_sep() {1305 self.parse_use_tree_glob_or_nested()?1306 } else {1307 // Recover from using a colon as path separator.1308 while self.eat_noexpect(&token::Colon) {1309 self.dcx()1310 .emit_err(errors::SingleColonImportPath { span: self.prev_token.span });13111312 // We parse the rest of the path and append it to the original prefix.1313 self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None)?;1314 prefix.span = lo.to(self.prev_token.span);1315 }13161317 UseTreeKind::Simple(self.parse_rename()?)1318 }1319 };13201321 Ok(UseTree { prefix, kind })1322 }13231324 /// Parses `*` or `{...}`.1325 fn parse_use_tree_glob_or_nested(&mut self) -> PResult<'a, UseTreeKind> {1326 Ok(if self.eat(exp!(Star)) {1327 UseTreeKind::Glob(self.prev_token.span)1328 } else {1329 let lo = self.token.span;1330 UseTreeKind::Nested {1331 items: self.parse_use_tree_list()?,1332 span: lo.to(self.prev_token.span),1333 }1334 })1335 }13361337 /// Parses a `UseTreeKind::Nested(list)`.1338 ///1339 /// ```text1340 /// USE_TREE_LIST = ∅ | (USE_TREE `,`)* USE_TREE [`,`]1341 /// ```1342 fn parse_use_tree_list(&mut self) -> PResult<'a, ThinVec<(UseTree, ast::NodeId)>> {1343 self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), |p| {1344 p.recover_vcs_conflict_marker();1345 Ok((p.parse_use_tree()?, DUMMY_NODE_ID))1346 })1347 .map(|(r, _)| r)1348 }13491350 fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {1351 if self.eat_keyword(exp!(As)) {1352 self.parse_ident_or_underscore().map(Some)1353 } else {1354 Ok(None)1355 }1356 }13571358 fn parse_ident_or_underscore(&mut self) -> PResult<'a, Ident> {1359 match self.token.ident() {1360 Some((ident @ Ident { name: kw::Underscore, .. }, IdentIsRaw::No)) => {1361 self.bump();1362 Ok(ident)1363 }1364 _ => self.parse_ident(),1365 }1366 }13671368 /// Parses `extern crate` links.1369 ///1370 /// # Examples1371 ///1372 /// ```ignore (illustrative)1373 /// extern crate foo;1374 /// extern crate bar as foo;1375 /// ```1376 fn parse_item_extern_crate(&mut self) -> PResult<'a, ItemKind> {1377 // Accept `extern crate name-like-this` for better diagnostics1378 let orig_ident = self.parse_crate_name_with_dashes()?;1379 let (orig_name, item_ident) = if let Some(rename) = self.parse_rename()? {1380 (Some(orig_ident.name), rename)1381 } else {1382 (None, orig_ident)1383 };1384 self.expect_semi()?;1385 Ok(ItemKind::ExternCrate(orig_name, item_ident))1386 }13871388 fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, Ident> {1389 let ident = if self.token.is_keyword(kw::SelfLower) {1390 self.parse_path_segment_ident()1391 } else {1392 self.parse_ident()1393 }?;13941395 let dash = exp!(Minus);1396 if self.token != dash.tok {1397 return Ok(ident);1398 }13991400 // Accept `extern crate name-like-this` for better diagnostics.1401 let mut dashes = vec![];1402 let mut idents = vec![];1403 while self.eat(dash) {1404 dashes.push(self.prev_token.span);1405 idents.push(self.parse_ident()?);1406 }14071408 let fixed_name_sp = ident.span.to(idents.last().unwrap().span);1409 let mut fixed_name = ident.name.to_string();1410 for part in idents {1411 write!(fixed_name, "_{}", part.name).unwrap();1412 }14131414 self.dcx().emit_err(errors::ExternCrateNameWithDashes {1415 span: fixed_name_sp,1416 sugg: errors::ExternCrateNameWithDashesSugg { dashes },1417 });14181419 Ok(Ident::from_str_and_span(&fixed_name, fixed_name_sp))1420 }14211422 /// Parses `extern` for foreign ABIs modules.1423 ///1424 /// `extern` is expected to have been consumed before calling this method.1425 ///1426 /// # Examples1427 ///1428 /// ```ignore (only-for-syntax-highlight)1429 /// extern "C" {}1430 /// extern {}1431 /// ```1432 fn parse_item_foreign_mod(1433 &mut self,1434 attrs: &mut AttrVec,1435 mut safety: Safety,1436 ) -> PResult<'a, ItemKind> {1437 let extern_span = self.prev_token_uninterpolated_span();1438 let abi = self.parse_abi(); // ABI?1439 // FIXME: This recovery should be tested better.1440 if safety == Safety::Default1441 && self.token.is_keyword(kw::Unsafe)1442 && self.look_ahead(1, |t| *t == token::OpenBrace)1443 {1444 self.expect(exp!(OpenBrace)).unwrap_err().emit();1445 safety = Safety::Unsafe(self.token.span);1446 let _ = self.eat_keyword(exp!(Unsafe));1447 }1448 Ok(ItemKind::ForeignMod(ast::ForeignMod {1449 extern_span,1450 safety,1451 abi,1452 items: self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?,1453 }))1454 }14551456 /// Parses a foreign item (one in an `extern { ... }` block).1457 pub fn parse_foreign_item(1458 &mut self,1459 force_collect: ForceCollect,1460 ) -> PResult<'a, Option<Option<Box<ForeignItem>>>> {1461 let fn_parse_mode = FnParseMode {1462 req_name: |_, is_dot_dot_dot| is_dot_dot_dot == IsDotDotDot::No,1463 context: FnContext::Free,1464 req_body: false,1465 };1466 Ok(self1467 .parse_item_(1468 fn_parse_mode,1469 force_collect,1470 AllowConstBlockItems::DoesNotMatter, // due to `ForeignItemKind::try_from` below1471 )?1472 .map(|Item { attrs, id, span, vis, kind, tokens }| {1473 let kind = match ForeignItemKind::try_from(kind) {1474 Ok(kind) => kind,1475 Err(kind) => match kind {1476 ItemKind::Const(ConstItem { ident, ty, rhs_kind, .. }) => {1477 let const_span = Some(span.with_hi(ident.span.lo()))1478 .filter(|span| span.can_be_used_for_suggestions());1479 self.dcx().emit_err(errors::ExternItemCannotBeConst {1480 ident_span: ident.span,1481 const_span,1482 });1483 ForeignItemKind::Static(Box::new(StaticItem {1484 ident,1485 ty,1486 mutability: Mutability::Not,1487 expr: match rhs_kind {1488 ConstItemRhsKind::Body { rhs } => rhs,1489 ConstItemRhsKind::TypeConst { rhs: Some(anon) } => {1490 Some(anon.value)1491 }1492 ConstItemRhsKind::TypeConst { rhs: None } => None,1493 },1494 safety: Safety::Default,1495 define_opaque: None,1496 eii_impls: ThinVec::default(),1497 }))1498 }1499 _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"),1500 },1501 };1502 Some(Box::new(Item { attrs, id, span, vis, kind, tokens }))1503 }))1504 }15051506 fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &'static str) -> Option<T> {1507 // FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`)1508 let span = self.psess.source_map().guess_head_span(span);1509 let descr = kind.descr();1510 let help = match kind {1511 ItemKind::DelegationMac(DelegationMac {1512 suffixes: DelegationSuffixes::Glob(_),1513 ..1514 }) => false,1515 _ => true,1516 };1517 self.dcx().emit_err(errors::BadItemKind { span, descr, ctx, help });1518 None1519 }15201521 fn is_use_closure(&self) -> bool {1522 if self.token.is_keyword(kw::Use) {1523 // Check if this could be a closure.1524 self.look_ahead(1, |token| {1525 // Move or Async here would be an error but still we're parsing a closure1526 let dist =1527 if token.is_keyword(kw::Move) || token.is_keyword(kw::Async) { 2 } else { 1 };15281529 self.look_ahead(dist, |token| matches!(token.kind, token::Or | token::OrOr))1530 })1531 } else {1532 false1533 }1534 }15351536 fn is_unsafe_foreign_mod(&self) -> bool {1537 // Look for `unsafe`.1538 if !self.token.is_keyword(kw::Unsafe) {1539 return false;1540 }1541 // Look for `extern`.1542 if !self.is_keyword_ahead(1, &[kw::Extern]) {1543 return false;1544 }15451546 // Look for the optional ABI string literal.1547 let n = if self.look_ahead(2, |t| t.can_begin_string_literal()) { 3 } else { 2 };15481549 // Look for the `{`. Use `tree_look_ahead` because the ABI (if present)1550 // might be a metavariable i.e. an invisible-delimited sequence, and1551 // `tree_look_ahead` will consider that a single element when looking1552 // ahead.1553 self.tree_look_ahead(n, |t| matches!(t, TokenTree::Delimited(_, _, Delimiter::Brace, _)))1554 == Some(true)1555 }15561557 fn parse_global_static_front_matter(&mut self, case: Case) -> Option<Safety> {1558 let is_global_static = if self.check_keyword_case(exp!(Static), case) {1559 // Check if this could be a closure.1560 !self.look_ahead(1, |token| {1561 if token.is_keyword_case(kw::Move, case) || token.is_keyword_case(kw::Use, case) {1562 return true;1563 }1564 matches!(token.kind, token::Or | token::OrOr)1565 })1566 } else {1567 // `$qual static`1568 (self.check_keyword_case(exp!(Unsafe), case)1569 || self.check_keyword_case(exp!(Safe), case))1570 && self.look_ahead(1, |t| t.is_keyword_case(kw::Static, case))1571 };15721573 if is_global_static {1574 let safety = self.parse_safety(case);1575 let _ = self.eat_keyword_case(exp!(Static), case);1576 Some(safety)1577 } else {1578 None1579 }1580 }15811582 /// Recover on `const mut` with `const` already eaten.1583 fn recover_const_mut(&mut self, const_span: Span) {1584 if self.eat_keyword(exp!(Mut)) {1585 let span = self.prev_token.span;1586 self.dcx()1587 .emit_err(errors::ConstGlobalCannotBeMutable { ident_span: span, const_span });1588 } else if self.eat_keyword(exp!(Let)) {1589 let span = self.prev_token.span;1590 self.dcx().emit_err(errors::ConstLetMutuallyExclusive { span: const_span.to(span) });1591 }1592 }15931594 fn parse_const_block_item(&mut self) -> PResult<'a, ConstBlockItem> {1595 self.expect_keyword(exp!(Const))?;1596 let const_span = self.prev_token.span;1597 self.psess.gated_spans.gate(sym::const_block_items, const_span);1598 let block = self.parse_block()?;1599 Ok(ConstBlockItem { id: DUMMY_NODE_ID, span: const_span.to(block.span), block })1600 }16011602 /// Parse a static item with the prefix `"static" "mut"?` already parsed and stored in1603 /// `mutability`.1604 ///1605 /// ```ebnf1606 /// Static = "static" "mut"? $ident ":" $ty (= $expr)? ";" ;1607 /// ```1608 fn parse_static_item(1609 &mut self,1610 safety: Safety,1611 mutability: Mutability,1612 ) -> PResult<'a, ItemKind> {1613 let ident = self.parse_ident()?;16141615 if self.token == TokenKind::Lt && self.may_recover() {1616 let generics = self.parse_generics()?;1617 self.dcx().emit_err(errors::StaticWithGenerics { span: generics.span });1618 }16191620 // Parse the type of a static item. That is, the `":" $ty` fragment.1621 // FIXME: This could maybe benefit from `.may_recover()`?1622 let ty = match (self.eat(exp!(Colon)), self.check(exp!(Eq)) | self.check(exp!(Semi))) {1623 (true, false) => self.parse_ty()?,1624 // If there wasn't a `:` or the colon was followed by a `=` or `;`, recover a missing1625 // type.1626 (colon, _) => self.recover_missing_global_item_type(colon, Some(mutability)),1627 };16281629 let expr = if self.eat(exp!(Eq)) { Some(self.parse_expr()?) } else { None };16301631 self.expect_semi()?;16321633 let item = StaticItem {1634 ident,1635 ty,1636 safety,1637 mutability,1638 expr,1639 define_opaque: None,1640 eii_impls: ThinVec::default(),1641 };1642 Ok(ItemKind::Static(Box::new(item)))1643 }16441645 /// Parse a constant item with the prefix `"const"` already parsed.1646 ///1647 /// If `const_arg` is true, any expression assigned to the const will be parsed1648 /// as a const_arg instead of a body expression.1649 ///1650 /// ```ebnf1651 /// Const = "const" ($ident | "_") Generics ":" $ty (= $expr)? WhereClause ";" ;1652 /// ```1653 fn parse_const_item(1654 &mut self,1655 const_arg: bool,1656 const_span: Span,1657 ) -> PResult<'a, (Ident, Generics, Box<Ty>, ConstItemRhsKind)> {1658 let ident = self.parse_ident_or_underscore()?;16591660 let mut generics = self.parse_generics()?;16611662 // Check the span for emptiness instead of the list of parameters in order to correctly1663 // recognize and subsequently flag empty parameter lists (`<>`) as unstable.1664 if !generics.span.is_empty() {1665 self.psess.gated_spans.gate(sym::generic_const_items, generics.span);1666 }16671668 // Parse the type of a constant item. That is, the `":" $ty` fragment.1669 // FIXME: This could maybe benefit from `.may_recover()`?1670 let ty = match (1671 self.eat(exp!(Colon)),1672 self.check(exp!(Eq)) | self.check(exp!(Semi)) | self.check_keyword(exp!(Where)),1673 ) {1674 (true, false) => self.parse_ty()?,1675 // If there wasn't a `:` or the colon was followed by a `=`, `;` or `where`, recover a missing type.1676 (colon, _) => self.recover_missing_global_item_type(colon, None),1677 };16781679 // Proactively parse a where-clause to be able to provide a good error message in case we1680 // encounter the item body following it.1681 let before_where_clause =1682 if self.may_recover() { self.parse_where_clause()? } else { WhereClause::default() };16831684 let rhs = match (self.eat(exp!(Eq)), const_arg) {1685 (true, true) => ConstItemRhsKind::TypeConst {1686 rhs: Some(self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct)?),1687 },1688 (true, false) => ConstItemRhsKind::Body { rhs: Some(self.parse_expr()?) },1689 (false, true) => ConstItemRhsKind::TypeConst { rhs: None },1690 (false, false) => ConstItemRhsKind::Body { rhs: None },1691 };16921693 let after_where_clause = self.parse_where_clause()?;16941695 // Provide a nice error message if the user placed a where-clause before the item body.1696 // Users may be tempted to write such code if they are still used to the deprecated1697 // where-clause location on type aliases and associated types. See also #89122.1698 if before_where_clause.has_where_token1699 && let Some(rhs_span) = rhs.span()1700 {1701 self.dcx().emit_err(errors::WhereClauseBeforeConstBody {1702 span: before_where_clause.span,1703 name: ident.span,1704 body: rhs_span,1705 sugg: if !after_where_clause.has_where_token {1706 self.psess.source_map().span_to_snippet(rhs_span).ok().map(|body_s| {1707 errors::WhereClauseBeforeConstBodySugg {1708 left: before_where_clause.span.shrink_to_lo(),1709 snippet: body_s,1710 right: before_where_clause.span.shrink_to_hi().to(rhs_span),1711 }1712 })1713 } else {1714 // FIXME(generic_const_items): Provide a structured suggestion to merge the first1715 // where-clause into the second one.1716 None1717 },1718 });1719 }17201721 // Merge the predicates of both where-clauses since either one can be relevant.1722 // If we didn't parse a body (which is valid for associated consts in traits) and we were1723 // allowed to recover, `before_where_clause` contains the predicates, otherwise they are1724 // in `after_where_clause`. Further, both of them might contain predicates iff two1725 // where-clauses were provided which is syntactically ill-formed but we want to recover from1726 // it and treat them as one large where-clause.1727 let mut predicates = before_where_clause.predicates;1728 predicates.extend(after_where_clause.predicates);1729 let where_clause = WhereClause {1730 has_where_token: before_where_clause.has_where_token1731 || after_where_clause.has_where_token,1732 predicates,1733 span: if after_where_clause.has_where_token {1734 after_where_clause.span1735 } else {1736 before_where_clause.span1737 },1738 };17391740 if where_clause.has_where_token {1741 self.psess.gated_spans.gate(sym::generic_const_items, where_clause.span);1742 }17431744 generics.where_clause = where_clause;17451746 if let Some(rhs) = self.try_recover_const_missing_semi(&rhs, const_span) {1747 return Ok((ident, generics, ty, ConstItemRhsKind::Body { rhs: Some(rhs) }));1748 }1749 self.expect_semi()?;17501751 Ok((ident, generics, ty, rhs))1752 }17531754 /// We were supposed to parse `":" $ty` but the `:` or the type was missing.1755 /// This means that the type is missing.1756 fn recover_missing_global_item_type(1757 &mut self,1758 colon_present: bool,1759 m: Option<Mutability>,1760 ) -> Box<Ty> {1761 // Construct the error and stash it away with the hope1762 // that typeck will later enrich the error with a type.1763 let kind = match m {1764 Some(Mutability::Mut) => "static mut",1765 Some(Mutability::Not) => "static",1766 None => "const",1767 };17681769 let colon = match colon_present {1770 true => "",1771 false => ":",1772 };17731774 let span = self.prev_token.span.shrink_to_hi();1775 let err = self.dcx().create_err(errors::MissingConstType { span, colon, kind });1776 err.stash(span, StashKey::ItemNoType);17771778 // The user intended that the type be inferred,1779 // so treat this as if the user wrote e.g. `const A: _ = expr;`.1780 Box::new(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID, tokens: None })1781 }17821783 /// Parses an enum declaration.1784 fn parse_item_enum(&mut self) -> PResult<'a, ItemKind> {1785 if self.token.is_keyword(kw::Struct) {1786 let span = self.prev_token.span.to(self.token.span);1787 let err = errors::EnumStructMutuallyExclusive { span };1788 if self.look_ahead(1, |t| t.is_ident()) {1789 self.bump();1790 self.dcx().emit_err(err);1791 } else {1792 return Err(self.dcx().create_err(err));1793 }1794 }17951796 let prev_span = self.prev_token.span;1797 let ident = self.parse_ident()?;1798 let mut generics = self.parse_generics()?;1799 generics.where_clause = self.parse_where_clause()?;18001801 // Possibly recover `enum Foo;` instead of `enum Foo {}`1802 let (variants, _) = if self.token == TokenKind::Semi {1803 self.dcx().emit_err(errors::UseEmptyBlockNotSemi { span: self.token.span });1804 self.bump();1805 (thin_vec![], Trailing::No)1806 } else {1807 self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), |p| {1808 p.parse_enum_variant(ident.span)1809 })1810 .map_err(|mut err| {1811 err.span_label(ident.span, "while parsing this enum");1812 // Try to recover `enum Foo { ident : Ty }`.1813 if self.prev_token.is_non_reserved_ident() && self.token == token::Colon {1814 let snapshot = self.create_snapshot_for_diagnostic();1815 self.bump();1816 match self.parse_ty() {1817 Ok(_) => {1818 err.span_suggestion_verbose(1819 prev_span,1820 "perhaps you meant to use `struct` here",1821 "struct",1822 Applicability::MaybeIncorrect,1823 );1824 }1825 Err(e) => {1826 e.cancel();1827 }1828 }1829 self.restore_snapshot(snapshot);1830 }1831 self.eat_to_tokens(&[exp!(CloseBrace)]);1832 self.bump(); // }1833 err1834 })?1835 };18361837 let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() };1838 Ok(ItemKind::Enum(ident, generics, enum_definition))1839 }18401841 fn parse_enum_variant(&mut self, span: Span) -> PResult<'a, Option<Variant>> {1842 self.recover_vcs_conflict_marker();1843 let variant_attrs = self.parse_outer_attributes()?;1844 self.recover_vcs_conflict_marker();1845 let help = "enum variants can be `Variant`, `Variant = <integer>`, \1846 `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`";1847 self.collect_tokens(None, variant_attrs, ForceCollect::No, |this, variant_attrs| {1848 let vlo = this.token.span;18491850 let vis = this.parse_visibility(FollowedByType::No)?;1851 if !this.recover_nested_adt_item(kw::Enum)? {1852 return Ok((None, Trailing::No, UsePreAttrPos::No));1853 }1854 let ident = this.parse_field_ident("enum", vlo)?;18551856 if this.token == token::Bang {1857 if let Err(err) = this.unexpected() {1858 err.with_note(msg!("macros cannot expand to enum variants")).emit();1859 }18601861 this.bump();1862 this.parse_delim_args()?;18631864 return Ok((None, Trailing::from(this.token == token::Comma), UsePreAttrPos::No));1865 }18661867 let struct_def = if this.check(exp!(OpenBrace)) {1868 // Parse a struct variant.1869 let (fields, recovered) =1870 match this.parse_record_struct_body("struct", ident.span, false) {1871 Ok((fields, recovered)) => (fields, recovered),1872 Err(mut err) => {1873 if this.token == token::Colon {1874 // We handle `enum` to `struct` suggestion in the caller.1875 return Err(err);1876 }1877 this.eat_to_tokens(&[exp!(CloseBrace)]);1878 this.bump(); // }1879 err.span_label(span, "while parsing this enum");1880 err.help(help);1881 let guar = err.emit();1882 (thin_vec![], Recovered::Yes(guar))1883 }1884 };1885 VariantData::Struct { fields, recovered }1886 } else if this.check(exp!(OpenParen)) {1887 let body = match this.parse_tuple_struct_body() {1888 Ok(body) => body,1889 Err(mut err) => {1890 if this.token == token::Colon {1891 // We handle `enum` to `struct` suggestion in the caller.1892 return Err(err);1893 }1894 this.eat_to_tokens(&[exp!(CloseParen)]);1895 this.bump(); // )1896 err.span_label(span, "while parsing this enum");1897 err.help(help);1898 err.emit();1899 thin_vec![]1900 }1901 };1902 VariantData::Tuple(body, DUMMY_NODE_ID)1903 } else {1904 VariantData::Unit(DUMMY_NODE_ID)1905 };19061907 let disr_expr = if this.eat(exp!(Eq)) {1908 Some(this.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?)1909 } else {1910 None1911 };19121913 let span = vlo.to(this.prev_token.span);1914 if ident.name == kw::Underscore {1915 this.psess.gated_spans.gate(sym::unnamed_enum_variants, span);1916 }1917 let vr = ast::Variant {1918 ident,1919 vis,1920 id: DUMMY_NODE_ID,1921 attrs: variant_attrs,1922 data: struct_def,1923 disr_expr,1924 span,1925 is_placeholder: false,1926 };19271928 Ok((Some(vr), Trailing::from(this.token == token::Comma), UsePreAttrPos::No))1929 })1930 .map_err(|mut err| {1931 err.help(help);1932 err1933 })1934 }19351936 /// Parses `struct Foo { ... }`.1937 fn parse_item_struct(&mut self) -> PResult<'a, ItemKind> {1938 let ident = self.parse_ident()?;19391940 let mut generics = self.parse_generics()?;19411942 // There is a special case worth noting here, as reported in issue #17904.1943 // If we are parsing a tuple struct it is the case that the where clause1944 // should follow the field list. Like so:1945 //1946 // struct Foo<T>(T) where T: Copy;1947 //1948 // If we are parsing a normal record-style struct it is the case1949 // that the where clause comes before the body, and after the generics.1950 // So if we look ahead and see a brace or a where-clause we begin1951 // parsing a record style struct.1952 //1953 // Otherwise if we look ahead and see a paren we parse a tuple-style1954 // struct.19551956 let vdata = if self.token.is_keyword(kw::Where) {1957 let tuple_struct_body;1958 (generics.where_clause, tuple_struct_body) =1959 self.parse_struct_where_clause(ident, generics.span)?;19601961 if let Some(body) = tuple_struct_body {1962 // If we see a misplaced tuple struct body: `struct Foo<T> where T: Copy, (T);`1963 let body = VariantData::Tuple(body, DUMMY_NODE_ID);1964 self.expect_semi()?;1965 body1966 } else if self.eat(exp!(Semi)) {1967 // If we see a: `struct Foo<T> where T: Copy;` style decl.1968 VariantData::Unit(DUMMY_NODE_ID)1969 } else {1970 // If we see: `struct Foo<T> where T: Copy { ... }`1971 let (fields, recovered) = self.parse_record_struct_body(1972 "struct",1973 ident.span,1974 generics.where_clause.has_where_token,1975 )?;1976 VariantData::Struct { fields, recovered }1977 }1978 // No `where` so: `struct Foo<T>;`1979 } else if self.eat(exp!(Semi)) {1980 VariantData::Unit(DUMMY_NODE_ID)1981 // Record-style struct definition1982 } else if self.token == token::OpenBrace {1983 let (fields, recovered) = self.parse_record_struct_body(1984 "struct",1985 ident.span,1986 generics.where_clause.has_where_token,1987 )?;1988 VariantData::Struct { fields, recovered }1989 // Tuple-style struct definition with optional where-clause.1990 } else if self.token == token::OpenParen {1991 let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID);1992 generics.where_clause = self.parse_where_clause()?;1993 self.expect_semi()?;1994 body1995 } else {1996 let err = errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token);1997 return Err(self.dcx().create_err(err));1998 };19992000 Ok(ItemKind::Struct(ident, generics, vdata))
Findings
✓ No findings reported for this file.