1use ast::token::IdentIsRaw;
2use rustc_ast as ast;
3use rustc_ast::ast::*;
4use rustc_ast::token::{self, InvisibleOrigin, MetaVarKind, TokenKind};
5use rustc_ast::tokenstream::TokenTree;
6use rustc_ast::util::case::Case;
7use rustc_ast_pretty::pprust;
8use rustc_errors::{Applicability, PResult};
9use rustc_session::lint::builtin::VARARGS_WITHOUT_PATTERN;
10use rustc_span::edition::Edition;
11use rustc_span::{ErrorGuaranteed, Ident, Span, kw, respan, sym};
12use thin_vec::ThinVec;
13use tracing::debug;
14
15use super::diagnostics::dummy_arg;
16use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
17use super::{
18 ExpKeywordPair, FollowedByType, ForceCollect, Parser, Recovered, Trailing, UsePreAttrPos,
19};
20use crate::diagnostics::{self, FnPointerCannotBeAsync, FnPointerCannotBeConst};
21use crate::exp;
22
23type ReqName = fn(Edition, IsDotDotDot) -> bool;
32
33#[derive(#[automatically_derived]
impl ::core::marker::Copy for IsDotDotDot { }Copy, #[automatically_derived]
impl ::core::clone::Clone for IsDotDotDot {
#[inline]
fn clone(&self) -> IsDotDotDot { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for IsDotDotDot {
#[inline]
fn eq(&self, other: &IsDotDotDot) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq)]
34pub(crate) enum IsDotDotDot {
35 Yes,
36 No,
37}
38
39#[derive(#[automatically_derived]
impl ::core::clone::Clone for FnParseMode {
#[inline]
fn clone(&self) -> FnParseMode {
let _: ::core::clone::AssertParamIsClone<ReqName>;
let _: ::core::clone::AssertParamIsClone<FnContext>;
let _: ::core::clone::AssertParamIsClone<bool>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for FnParseMode { }Copy)]
47pub(crate) struct FnParseMode {
48 pub(super) req_name: ReqName,
74 pub(super) context: FnContext,
77 pub(super) req_body: bool,
96}
97
98#[derive(#[automatically_derived]
impl ::core::clone::Clone for FnContext {
#[inline]
fn clone(&self) -> FnContext { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for FnContext { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for FnContext {
#[inline]
fn eq(&self, other: &FnContext) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for FnContext {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
101pub(crate) enum FnContext {
102 Free,
104 FunctionPtrType,
106 Trait,
108 Impl,
110}
111
112impl<'a> Parser<'a> {
114 pub(super) fn parse_fn(
116 &mut self,
117 attrs: &mut AttrVec,
118 fn_parse_mode: FnParseMode,
119 sig_lo: Span,
120 vis: &Visibility,
121 case: Case,
122 ) -> PResult<'a, (Ident, FnSig, Generics, Option<Box<FnContract>>, Option<Box<Block>>)> {
123 let fn_span = self.token.span;
124 let header = self.parse_fn_front_matter(vis, case, FrontMatterParsingMode::Function)?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; let decl = match self.parse_fn_decl(&fn_parse_mode, AllowPlus::Yes, RecoverReturnSign::Yes)
128 {
129 Ok(decl) => decl,
130 Err(old_err) => {
131 if self.token.is_keyword(kw::For) {
133 old_err.cancel();
134 return Err(self.dcx().create_err(diagnostics::FnTypoWithImpl { fn_span }));
135 } else {
136 return Err(old_err);
137 }
138 }
139 };
140
141 let fn_params_end = self.prev_token.span.shrink_to_hi();
144
145 let contract = self.parse_contract()?;
146
147 generics.where_clause = self.parse_where_clause()?; let fn_params_end =
151 if generics.where_clause.has_where_token { Some(fn_params_end) } else { None };
152
153 let mut sig_hi = self.prev_token.span;
154 let body =
156 self.parse_fn_body(attrs, &ident, &mut sig_hi, fn_parse_mode.req_body, fn_params_end)?;
157 let fn_sig_span = sig_lo.to(sig_hi);
158 Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, contract, body))
159 }
160
161 fn error_fn_body_not_found(
163 &mut self,
164 ident_span: Span,
165 req_body: bool,
166 fn_params_end: Option<Span>,
167 ) -> PResult<'a, ErrorGuaranteed> {
168 let expected: &[_] =
169 if req_body { &[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)] } else { &[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Semi,
token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi), crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)] };
170 match self.expected_one_of_not_found(&[], expected) {
171 Ok(error_guaranteed) => Ok(error_guaranteed),
172 Err(mut err) => {
173 if self.token == token::CloseBrace {
174 err.span_label(ident_span, "while parsing this `fn`");
177 Ok(err.emit())
178 } else if self.token == token::RArrow
179 && let Some(fn_params_end) = fn_params_end
180 {
181 let fn_trait_span =
187 [sym::FnOnce, sym::FnMut, sym::Fn].into_iter().find_map(|symbol| {
188 if self.prev_token.is_ident_named(symbol) {
189 Some(self.prev_token.span)
190 } else {
191 None
192 }
193 });
194
195 let arrow_span = self.token.span;
200 let ty_span = match self.parse_ret_ty(
201 AllowPlus::Yes,
202 RecoverQPath::Yes,
203 RecoverReturnSign::Yes,
204 ) {
205 Ok(ty_span) => ty_span.span().shrink_to_hi(),
206 Err(parse_error) => {
207 parse_error.cancel();
208 return Err(err);
209 }
210 };
211 let ret_ty_span = arrow_span.to(ty_span);
212
213 if let Some(fn_trait_span) = fn_trait_span {
214 err.subdiagnostic(diagnostics::FnTraitMissingParen { span: fn_trait_span });
217 } else if let Ok(snippet) = self.psess.source_map().span_to_snippet(ret_ty_span)
218 {
219 err.primary_message(
223 "return type should be specified after the function parameters",
224 );
225 err.subdiagnostic(diagnostics::MisplacedReturnType {
226 fn_params_end,
227 snippet,
228 ret_ty_span,
229 });
230 }
231 Err(err)
232 } else {
233 Err(err)
234 }
235 }
236 }
237 }
238
239 fn parse_fn_body(
243 &mut self,
244 attrs: &mut AttrVec,
245 ident: &Ident,
246 sig_hi: &mut Span,
247 req_body: bool,
248 fn_params_end: Option<Span>,
249 ) -> PResult<'a, Option<Box<Block>>> {
250 let has_semi = if req_body {
251 self.token == TokenKind::Semi
252 } else {
253 self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Semi,
token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi))
255 };
256 let (inner_attrs, body) = if has_semi {
257 self.expect_semi()?;
259 *sig_hi = self.prev_token.span;
260 (AttrVec::new(), None)
261 } else if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) || self.token.is_metavar_block() {
262 let prev_in_fn_body = self.in_fn_body;
263 self.in_fn_body = true;
264 let res = self.parse_block_common(self.token.span, BlockCheckMode::Default, None).map(
265 |(attrs, mut body)| {
266 if let Some(guar) = self.fn_body_missing_semi_guar.take() {
267 body.stmts.push(self.mk_stmt(
268 body.span,
269 StmtKind::Expr(self.mk_expr(body.span, ExprKind::Err(guar))),
270 ));
271 }
272 (attrs, Some(body))
273 },
274 );
275 self.in_fn_body = prev_in_fn_body;
276 res?
277 } else if self.token == token::Eq {
278 self.bump(); let eq_sp = self.prev_token.span;
281 let _ = self.parse_expr()?;
282 self.expect_semi()?; let span = eq_sp.to(self.prev_token.span);
284 let guar = self.dcx().emit_err(diagnostics::FunctionBodyEqualsExpr {
285 span,
286 sugg: diagnostics::FunctionBodyEqualsExprSugg {
287 eq: eq_sp,
288 semi: self.prev_token.span,
289 },
290 });
291 (AttrVec::new(), Some(self.mk_block_err(span, guar)))
292 } else {
293 self.error_fn_body_not_found(ident.span, req_body, fn_params_end)?;
294 (AttrVec::new(), None)
295 };
296 attrs.extend(inner_attrs);
297 Ok(body)
298 }
299
300 pub(super) fn check_fn_front_matter(&mut self, check_pub: bool, case: Case) -> bool {
305 const ALL_QUALS: &[ExpKeywordPair] = &[
306 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Pub,
token_type: crate::parser::token_type::TokenType::KwPub,
}exp!(Pub),
307 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Gen,
token_type: crate::parser::token_type::TokenType::KwGen,
}exp!(Gen),
308 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Const,
token_type: crate::parser::token_type::TokenType::KwConst,
}exp!(Const),
309 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Async,
token_type: crate::parser::token_type::TokenType::KwAsync,
}exp!(Async),
310 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Unsafe,
token_type: crate::parser::token_type::TokenType::KwUnsafe,
}exp!(Unsafe),
311 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Safe,
token_type: crate::parser::token_type::TokenType::KwSafe,
}exp!(Safe),
312 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Extern,
token_type: crate::parser::token_type::TokenType::KwExtern,
}exp!(Extern),
313 ];
314
315 let quals: &[_] = if check_pub {
320 ALL_QUALS
321 } else {
322 &[crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Gen,
token_type: crate::parser::token_type::TokenType::KwGen,
}exp!(Gen), crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Const,
token_type: crate::parser::token_type::TokenType::KwConst,
}exp!(Const), crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Async,
token_type: crate::parser::token_type::TokenType::KwAsync,
}exp!(Async), crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Unsafe,
token_type: crate::parser::token_type::TokenType::KwUnsafe,
}exp!(Unsafe), crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Safe,
token_type: crate::parser::token_type::TokenType::KwSafe,
}exp!(Safe), crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Extern,
token_type: crate::parser::token_type::TokenType::KwExtern,
}exp!(Extern)]
323 };
324 self.check_keyword_case(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Fn,
token_type: crate::parser::token_type::TokenType::KwFn,
}exp!(Fn), case) || quals.iter().any(|&exp| self.check_keyword_case(exp, case))
327 && self.look_ahead(1, |t| {
328 t.is_keyword_case(kw::Fn, case)
330 || (
332 (
333 t.is_non_raw_ident_where(|i|
334 quals.iter().any(|exp| exp.kw == i.name)
335 && i.is_reserved()
337 )
338 || case == Case::Insensitive
339 && t.is_non_raw_ident_where(|i| quals.iter().any(|exp| {
340 exp.kw.as_str() == i.name.as_str().to_lowercase()
341 }))
342 )
343 && !self.is_unsafe_foreign_mod()
345 && !self.is_async_gen_block()
347 && !self.is_keyword_ahead(2, &[kw::Auto, kw::Trait, kw::Impl])
349 )
350 })
351 || self.check_keyword_case(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Extern,
token_type: crate::parser::token_type::TokenType::KwExtern,
}exp!(Extern), case)
353 && self.look_ahead(1, |t| t.can_begin_string_literal())
357 && (self.tree_look_ahead(2, |tt| {
358 match tt {
359 TokenTree::Token(t, _) => t.is_keyword_case(kw::Fn, case),
360 TokenTree::Delimited(..) => false,
361 }
362 }) == Some(true) ||
363 (self.may_recover()
366 && self.tree_look_ahead(2, |tt| {
367 match tt {
368 TokenTree::Token(t, _) =>
369 ALL_QUALS.iter().any(|exp| {
370 t.is_keyword(exp.kw)
371 }),
372 TokenTree::Delimited(..) => false,
373 }
374 }) == Some(true)
375 && self.tree_look_ahead(3, |tt| {
376 match tt {
377 TokenTree::Token(t, _) => t.is_keyword_case(kw::Fn, case),
378 TokenTree::Delimited(..) => false,
379 }
380 }) == Some(true)
381 )
382 )
383 }
384
385 pub(super) fn parse_fn_front_matter(
400 &mut self,
401 orig_vis: &Visibility,
402 case: Case,
403 parsing_mode: FrontMatterParsingMode,
404 ) -> PResult<'a, FnHeader> {
405 let sp_start = self.token.span;
406 let constness = self.parse_constness(case);
407 if parsing_mode == FrontMatterParsingMode::FunctionPtrType
408 && let Const::Yes(const_span) = constness
409 {
410 self.dcx().emit_err(FnPointerCannotBeConst {
411 span: const_span,
412 suggestion: const_span.until(self.token.span),
413 });
414 }
415
416 let async_start_sp = self.token.span;
417 let coroutine_kind = self.parse_coroutine_kind(case);
418 if parsing_mode == FrontMatterParsingMode::FunctionPtrType
419 && let Some(ast::CoroutineKind::Async { span: async_span, .. }) = coroutine_kind
420 {
421 self.dcx().emit_err(FnPointerCannotBeAsync {
422 span: async_span,
423 suggestion: async_span.until(self.token.span),
424 });
425 }
426 let unsafe_start_sp = self.token.span;
429 let safety = self.parse_safety(case);
430
431 let ext_start_sp = self.token.span;
432 let ext = self.parse_extern(case);
433
434 if let Some(CoroutineKind::Async { span, .. }) = coroutine_kind {
435 if span.is_rust_2015() {
436 self.dcx().emit_err(diagnostics::AsyncFnIn2015 {
437 span,
438 help: diagnostics::HelpUseLatestEdition::new(),
439 });
440 }
441 }
442
443 match coroutine_kind {
444 Some(CoroutineKind::Gen { span, .. }) | Some(CoroutineKind::AsyncGen { span, .. }) => {
445 self.psess.gated_spans.gate(sym::gen_blocks, span);
446 }
447 Some(CoroutineKind::Async { .. }) | None => {}
448 }
449
450 if !self.eat_keyword_case(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Fn,
token_type: crate::parser::token_type::TokenType::KwFn,
}exp!(Fn), case) {
451 match self.expect_one_of(&[], &[]) {
455 Ok(Recovered::Yes(_)) => {}
456 Ok(Recovered::No) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
457 Err(mut err) => {
458 enum WrongKw {
460 Duplicated(Span),
461 Misplaced(Span),
462 MisplacedDisallowedQualifier,
467 }
468
469 let mut recover_constness = constness;
471 let mut recover_coroutine_kind = coroutine_kind;
472 let mut recover_safety = safety;
473 let wrong_kw = if self.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Const,
token_type: crate::parser::token_type::TokenType::KwConst,
}exp!(Const)) {
476 match constness {
477 Const::Yes(sp) => Some(WrongKw::Duplicated(sp)),
478 Const::No => {
479 recover_constness = Const::Yes(self.token.span);
480 match parsing_mode {
481 FrontMatterParsingMode::Function => {
482 Some(WrongKw::Misplaced(async_start_sp))
483 }
484 FrontMatterParsingMode::FunctionPtrType => {
485 self.dcx().emit_err(FnPointerCannotBeConst {
486 span: self.token.span,
487 suggestion: self
488 .token
489 .span
490 .with_lo(self.prev_token.span.hi()),
491 });
492 Some(WrongKw::MisplacedDisallowedQualifier)
493 }
494 }
495 }
496 }
497 } else if self.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Async,
token_type: crate::parser::token_type::TokenType::KwAsync,
}exp!(Async)) {
498 match coroutine_kind {
499 Some(CoroutineKind::Async { span, .. }) => {
500 Some(WrongKw::Duplicated(span))
501 }
502 Some(CoroutineKind::AsyncGen { span, .. }) => {
503 Some(WrongKw::Duplicated(span))
504 }
505 Some(CoroutineKind::Gen { .. }) => {
506 recover_coroutine_kind = Some(CoroutineKind::AsyncGen {
507 span: self.token.span,
508 closure_id: DUMMY_NODE_ID,
509 return_impl_trait_id: DUMMY_NODE_ID,
510 });
511 Some(WrongKw::Misplaced(unsafe_start_sp))
513 }
514 None => {
515 recover_coroutine_kind = Some(CoroutineKind::Async {
516 span: self.token.span,
517 closure_id: DUMMY_NODE_ID,
518 return_impl_trait_id: DUMMY_NODE_ID,
519 });
520 match parsing_mode {
521 FrontMatterParsingMode::Function => {
522 Some(WrongKw::Misplaced(async_start_sp))
523 }
524 FrontMatterParsingMode::FunctionPtrType => {
525 self.dcx().emit_err(FnPointerCannotBeAsync {
526 span: self.token.span,
527 suggestion: self
528 .token
529 .span
530 .with_lo(self.prev_token.span.hi()),
531 });
532 Some(WrongKw::MisplacedDisallowedQualifier)
533 }
534 }
535 }
536 }
537 } else if self.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Unsafe,
token_type: crate::parser::token_type::TokenType::KwUnsafe,
}exp!(Unsafe)) {
538 match safety {
539 Safety::Unsafe(sp) => Some(WrongKw::Duplicated(sp)),
540 Safety::Safe(sp) => {
541 recover_safety = Safety::Unsafe(self.token.span);
542 Some(WrongKw::Misplaced(sp))
543 }
544 Safety::Default => {
545 recover_safety = Safety::Unsafe(self.token.span);
546 Some(WrongKw::Misplaced(ext_start_sp))
547 }
548 }
549 } else if self.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Safe,
token_type: crate::parser::token_type::TokenType::KwSafe,
}exp!(Safe)) {
550 match safety {
551 Safety::Safe(sp) => Some(WrongKw::Duplicated(sp)),
552 Safety::Unsafe(sp) => {
553 recover_safety = Safety::Safe(self.token.span);
554 Some(WrongKw::Misplaced(sp))
555 }
556 Safety::Default => {
557 recover_safety = Safety::Safe(self.token.span);
558 Some(WrongKw::Misplaced(ext_start_sp))
559 }
560 }
561 } else {
562 None
563 };
564
565 if let Some(WrongKw::Duplicated(original_sp)) = wrong_kw {
567 let original_kw = self
568 .span_to_snippet(original_sp)
569 .expect("Span extracted directly from keyword should always work");
570
571 err.span_suggestion_verbose(
572 self.token_uninterpolated_span(),
573 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` already used earlier, remove this one",
original_kw))
})format!("`{original_kw}` already used earlier, remove this one"),
574 "",
575 Applicability::MachineApplicable,
576 )
577 .span_note(original_sp, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` first seen here",
original_kw))
})format!("`{original_kw}` first seen here"));
578 }
579 else if let Some(WrongKw::Misplaced(correct_pos_sp)) = wrong_kw {
581 let correct_pos_sp = correct_pos_sp.to(self.prev_token.span);
582 if let Ok(current_qual) = self.span_to_snippet(correct_pos_sp) {
583 let misplaced_qual_sp = self.token_uninterpolated_span();
584 let misplaced_qual = self.span_to_snippet(misplaced_qual_sp).unwrap();
585
586 err.span_suggestion_verbose(
587 correct_pos_sp.to(misplaced_qual_sp),
588 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` must come before `{1}`",
misplaced_qual, current_qual))
})format!("`{misplaced_qual}` must come before `{current_qual}`"),
589 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} {1}", misplaced_qual,
current_qual))
})format!("{misplaced_qual} {current_qual}"),
590 Applicability::MachineApplicable,
591 ).note("keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`");
592 }
593 }
594 else if self.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Pub,
token_type: crate::parser::token_type::TokenType::KwPub,
}exp!(Pub)) {
596 let sp = sp_start.to(self.prev_token.span);
597 if let Ok(snippet) = self.span_to_snippet(sp) {
598 let current_vis = match self.parse_visibility(FollowedByType::No) {
599 Ok(v) => v,
600 Err(d) => {
601 d.cancel();
602 return Err(err);
603 }
604 };
605 let vs = pprust::vis_to_string(¤t_vis);
606 let vs = vs.trim_end();
607
608 if #[allow(non_exhaustive_omitted_patterns)] match orig_vis.kind {
VisibilityKind::Inherited => true,
_ => false,
}matches!(orig_vis.kind, VisibilityKind::Inherited) {
610 err.span_suggestion_verbose(
611 sp_start.to(self.prev_token.span),
612 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("visibility `{0}` must come before `{1}`",
vs, snippet))
})format!("visibility `{vs}` must come before `{snippet}`"),
613 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} {1}", vs, snippet))
})format!("{vs} {snippet}"),
614 Applicability::MachineApplicable,
615 );
616 }
617 else {
619 err.span_suggestion_verbose(
620 current_vis.span,
621 "there is already a visibility modifier, remove one",
622 "",
623 Applicability::MachineApplicable,
624 )
625 .span_note(orig_vis.span, "explicit visibility first seen here");
626 }
627 }
628 }
629
630 if let Some(wrong_kw) = wrong_kw
633 && self.may_recover()
634 && self.look_ahead(1, |tok| tok.is_keyword_case(kw::Fn, case))
635 {
636 self.bump();
638 self.bump();
639 if #[allow(non_exhaustive_omitted_patterns)] match wrong_kw {
WrongKw::MisplacedDisallowedQualifier => true,
_ => false,
}matches!(wrong_kw, WrongKw::MisplacedDisallowedQualifier) {
642 err.cancel();
643 } else {
644 err.emit();
645 }
646 return Ok(FnHeader {
647 constness: recover_constness,
648 safety: recover_safety,
649 coroutine_kind: recover_coroutine_kind,
650 ext,
651 });
652 }
653
654 return Err(err);
655 }
656 }
657 }
658
659 Ok(FnHeader { constness, safety, coroutine_kind, ext })
660 }
661
662 pub(super) fn parse_fn_decl(
664 &mut self,
665 fn_parse_mode: &FnParseMode,
666 ret_allow_plus: AllowPlus,
667 recover_return_sign: RecoverReturnSign,
668 ) -> PResult<'a, Box<FnDecl>> {
669 Ok(Box::new(FnDecl {
670 inputs: self.parse_fn_params(fn_parse_mode)?,
671 output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, recover_return_sign)?,
672 }))
673 }
674
675 pub(super) fn parse_fn_params(
677 &mut self,
678 fn_parse_mode: &FnParseMode,
679 ) -> PResult<'a, ThinVec<Param>> {
680 let mut first_param = true;
681 if self.token != TokenKind::OpenParen
683 && !self.token.is_keyword(kw::For)
685 {
686 self.dcx().emit_err(diagnostics::MissingFnParams {
688 span: self.prev_token.span.shrink_to_hi(),
689 });
690 return Ok(ThinVec::new());
691 }
692
693 let (mut params, _) = self.parse_paren_comma_seq(|p| {
694 p.recover_vcs_conflict_marker();
695 let snapshot = p.create_snapshot_for_diagnostic();
696 let param = p.parse_param_general(fn_parse_mode, first_param, true).or_else(|e| {
697 let guar = e.emit();
698 let lo = if let TokenKind::OpenParen = p.prev_token.kind {
702 p.prev_token.span.shrink_to_hi()
703 } else {
704 p.prev_token.span
705 };
706 p.restore_snapshot(snapshot);
707 p.eat_to_tokens(&[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma), crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen)]);
709 Ok(dummy_arg(Ident::new(sym::dummy, lo.to(p.prev_token.span)), guar))
711 });
712 first_param = false;
714 param
715 })?;
716 self.deduplicate_recovered_params_names(&mut params);
718 Ok(params)
719 }
720
721 pub(super) fn parse_param_general(
726 &mut self,
727 fn_parse_mode: &FnParseMode,
728 first_param: bool,
729 recover_arg_parse: bool,
730 ) -> PResult<'a, Param> {
731 let lo = self.token.span;
732 let attrs = self.parse_outer_attributes()?;
733 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
734 if let Some(mut param) = this.parse_self_param()? {
736 param.attrs = attrs;
737 let res = if first_param { Ok(param) } else { this.recover_bad_self_param(param) };
738 return Ok((res?, Trailing::No, UsePreAttrPos::No));
739 }
740
741 let is_dot_dot_dot = if this.token.kind == token::DotDotDot {
742 IsDotDotDot::Yes
743 } else {
744 IsDotDotDot::No
745 };
746 let is_name_required = (fn_parse_mode.req_name)(
747 this.token.span.with_neighbor(this.prev_token.span).edition(),
748 is_dot_dot_dot,
749 );
750 let is_name_required = if is_name_required && is_dot_dot_dot == IsDotDotDot::Yes {
751 this.psess.buffer_lint(
752 VARARGS_WITHOUT_PATTERN,
753 this.token.span,
754 ast::CRATE_NODE_ID,
755 diagnostics::VarargsWithoutPattern { span: this.token.span },
756 );
757 false
758 } else {
759 is_name_required
760 };
761 let (pat, ty) = if is_name_required || this.is_named_param() {
762 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/function.rs:762",
"rustc_parse::parser::function", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/function.rs"),
::tracing_core::__macro_support::Option::Some(762u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::function"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("parse_param_general parse_pat (is_name_required:{0})",
is_name_required) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
763 let (pat, colon) = this.parse_fn_param_pat_colon()?;
764 if !colon {
765 let mut err = this.unexpected().unwrap_err();
766 let pat_span = pat.span;
767 return if let Some(ident) = this.parameter_without_type(
768 &mut err,
769 pat,
770 is_name_required,
771 first_param,
772 fn_parse_mode,
773 ) {
774 let guar = err.emit();
775 let mut arg = dummy_arg(ident, guar);
776 arg.span = pat_span;
777 Ok((arg, Trailing::No, UsePreAttrPos::No))
778 } else {
779 Err(err)
780 };
781 }
782
783 this.eat_incorrect_doc_comment_for_param_type();
784 (pat, this.parse_ty_for_param()?)
785 } else {
786 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/function.rs:786",
"rustc_parse::parser::function", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/function.rs"),
::tracing_core::__macro_support::Option::Some(786u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::function"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("parse_param_general ident_to_pat")
as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("parse_param_general ident_to_pat");
787 let parser_snapshot_before_ty = this.create_snapshot_for_diagnostic();
788 this.eat_incorrect_doc_comment_for_param_type();
789 let mut ty = this.parse_ty_for_param();
790
791 if let Ok(t) = &ty {
792 if let TyKind::Path(_, Path { segments, .. }) = &t.kind
794 && let Some(segment) = segments.last()
795 && let Some(guar) =
796 this.check_trailing_angle_brackets(segment, &[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen)])
797 {
798 return Ok((
799 dummy_arg(segment.ident, guar),
800 Trailing::No,
801 UsePreAttrPos::No,
802 ));
803 }
804
805 if this.token != token::Comma && this.token != token::CloseParen {
806 ty = this.unexpected_any();
809 }
810 }
811 match ty {
812 Ok(ty) => {
813 let pat = this.mk_pat(ty.span, PatKind::Missing);
814 (Box::new(pat), ty)
815 }
816 Err(err) if this.token == token::DotDotDot => return Err(err),
818 Err(err) if this.unmatched_angle_bracket_count > 0 => return Err(err),
819 Err(err) if recover_arg_parse => {
820 err.cancel();
822 this.restore_snapshot(parser_snapshot_before_ty);
823 this.recover_arg_parse(fn_parse_mode.context)?
824 }
825 Err(err) => return Err(err),
826 }
827 };
828
829 let span = lo.to(this.prev_token.span);
830
831 Ok((
832 Param { attrs, id: ast::DUMMY_NODE_ID, is_placeholder: false, pat, span, ty },
833 Trailing::No,
834 UsePreAttrPos::No,
835 ))
836 })
837 }
838
839 fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
841 let expect_self_ident = |this: &mut Self| match this.token.ident() {
843 Some((ident, IdentIsRaw::No)) => {
844 this.bump();
845 ident
846 }
847 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
848 };
849 let is_lifetime = |this: &Self, n| this.look_ahead(n, |t| t.is_lifetime());
851 let is_isolated_self = |this: &Self, n| {
853 this.is_keyword_ahead(n, &[kw::SelfLower])
854 && this.look_ahead(n + 1, |t| t != &token::PathSep)
855 };
856 let is_isolated_pin_const_self = |this: &Self, n| {
858 this.look_ahead(n, |token| token.is_ident_named(sym::pin))
859 && this.is_keyword_ahead(n + 1, &[kw::Const])
860 && is_isolated_self(this, n + 2)
861 };
862 let is_isolated_mut_self =
864 |this: &Self, n| this.is_keyword_ahead(n, &[kw::Mut]) && is_isolated_self(this, n + 1);
865 let is_isolated_pin_mut_self = |this: &Self, n| {
867 this.look_ahead(n, |token| token.is_ident_named(sym::pin))
868 && is_isolated_mut_self(this, n + 1)
869 };
870 let parse_self_possibly_typed = |this: &mut Self, m| {
872 let eself_ident = expect_self_ident(this);
873 let eself_hi = this.prev_token.span;
874 let eself = if this.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Colon,
token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon)) {
875 SelfKind::Explicit(this.parse_ty()?, m)
876 } else {
877 SelfKind::Value(m)
878 };
879 Ok((eself, eself_ident, eself_hi))
880 };
881 let expect_self_ident_not_typed =
882 |this: &mut Self, modifier: &SelfKind, modifier_span: Span| {
883 let eself_ident = expect_self_ident(this);
884
885 if this.may_recover() && this.eat_noexpect(&token::Colon) {
887 let snap = this.create_snapshot_for_diagnostic();
888 match this.parse_ty() {
889 Ok(ty) => {
890 this.dcx().emit_err(diagnostics::IncorrectTypeOnSelf {
891 span: ty.span,
892 move_self_modifier: diagnostics::MoveSelfModifier {
893 removal_span: modifier_span,
894 insertion_span: ty.span.shrink_to_lo(),
895 modifier: modifier.to_ref_suggestion(),
896 },
897 });
898 }
899 Err(diag) => {
900 diag.cancel();
901 this.restore_snapshot(snap);
902 }
903 }
904 }
905 eself_ident
906 };
907 let recover_self_ptr = |this: &mut Self| {
909 this.dcx().emit_err(diagnostics::SelfArgumentPointer { span: this.token.span });
910
911 Ok((SelfKind::Value(Mutability::Not), expect_self_ident(this), this.prev_token.span))
912 };
913
914 let eself_lo = self.token.span;
918 let (eself, eself_ident, eself_hi) = match self.token.uninterpolate().kind {
919 token::And => {
920 let has_lifetime = is_lifetime(self, 1);
921 let skip_lifetime_count = has_lifetime as usize;
922 let eself = if is_isolated_self(self, skip_lifetime_count + 1) {
923 self.bump(); let lifetime = has_lifetime.then(|| self.expect_lifetime());
926 SelfKind::Region(lifetime, Mutability::Not)
927 } else if is_isolated_mut_self(self, skip_lifetime_count + 1) {
928 self.bump(); let lifetime = has_lifetime.then(|| self.expect_lifetime());
931 self.bump(); SelfKind::Region(lifetime, Mutability::Mut)
933 } else if is_isolated_pin_const_self(self, skip_lifetime_count + 1) {
934 self.bump(); let lifetime = has_lifetime.then(|| self.expect_lifetime());
937 self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
938 self.bump(); self.bump(); SelfKind::Pinned(lifetime, Mutability::Not)
941 } else if is_isolated_pin_mut_self(self, skip_lifetime_count + 1) {
942 self.bump(); let lifetime = has_lifetime.then(|| self.expect_lifetime());
945 self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
946 self.bump(); self.bump(); SelfKind::Pinned(lifetime, Mutability::Mut)
949 } else {
950 return Ok(None);
952 };
953 let hi = self.token.span;
954 let self_ident = expect_self_ident_not_typed(self, &eself, eself_lo.until(hi));
955 (eself, self_ident, hi)
956 }
957 token::Star if is_isolated_self(self, 1) => {
959 self.bump();
960 recover_self_ptr(self)?
961 }
962 token::Star
964 if self.look_ahead(1, |t| t.is_mutability()) && is_isolated_self(self, 2) =>
965 {
966 self.bump();
967 self.bump();
968 recover_self_ptr(self)?
969 }
970 token::Ident(..) if is_isolated_self(self, 0) => {
972 parse_self_possibly_typed(self, Mutability::Not)?
973 }
974 token::Ident(..) if is_isolated_mut_self(self, 0) => {
976 self.bump();
977 parse_self_possibly_typed(self, Mutability::Mut)?
978 }
979 _ => return Ok(None),
980 };
981
982 let eself = respan(eself_lo.to(eself_hi), eself);
983 Ok(Some(Param::from_self(AttrVec::default(), eself, eself_ident)))
984 }
985
986 fn is_named_param(&self) -> bool {
987 let offset = match &self.token.kind {
988 token::OpenInvisible(origin) => match origin {
989 InvisibleOrigin::MetaVar(MetaVarKind::Pat(_)) => {
990 return self.check_noexpect_past_close_delim(&token::Colon);
991 }
992 _ => 0,
993 },
994 token::And | token::AndAnd => 1,
995 _ if self.token.is_keyword(kw::Mut) => 1,
996 _ => 0,
997 };
998
999 self.look_ahead(offset, |t| t.is_ident())
1000 && self.look_ahead(offset + 1, |t| t == &token::Colon)
1001 }
1002
1003 pub(super) fn recover_self_param(&mut self) -> bool {
1004 #[allow(non_exhaustive_omitted_patterns)] match self.parse_outer_attributes().and_then(|_|
self.parse_self_param()).map_err(|e| e.cancel()) {
Ok(Some(_)) => true,
_ => false,
}matches!(
1005 self.parse_outer_attributes()
1006 .and_then(|_| self.parse_self_param())
1007 .map_err(|e| e.cancel()),
1008 Ok(Some(_))
1009 )
1010 }
1011}
1012
1013#[derive(#[automatically_derived]
impl ::core::marker::Copy for FrontMatterParsingMode { }Copy, #[automatically_derived]
impl ::core::clone::Clone for FrontMatterParsingMode {
#[inline]
fn clone(&self) -> FrontMatterParsingMode { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for FrontMatterParsingMode {
#[inline]
fn eq(&self, other: &FrontMatterParsingMode) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for FrontMatterParsingMode {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
1014pub(crate) enum FrontMatterParsingMode {
1015 Function,
1017 FunctionPtrType,
1020}