1use rustc_ast as ast;
2use rustc_ast::ast::*;
3use rustc_ast::token::{self, InvisibleOrigin, MetaVarKind, TokenKind};
4use rustc_ast::tokenstream::TokenTree;
5use rustc_ast::util::case::Case;
6use rustc_ast_pretty::pprust;
7use rustc_errors::{Applicability, PResult};
8use rustc_lint_defs::builtin::VARARGS_WITHOUT_PATTERN;
9use rustc_span::edition::Edition;
10use rustc_span::{ErrorGuaranteed, Ident, Span, kw, respan, sym};
11use thin_vec::ThinVec;
12use tracing::debug;
13
14use super::diagnostics::dummy_arg;
15use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
16use super::{
17 ExpKeywordPair, FollowedByType, ForceCollect, Parser, Recovered, Trailing, UsePreAttrPos,
18};
19use crate::diagnostics::{self, FnPointerCannotBeAsync, FnPointerCannotBeConst};
20use crate::exp;
21
22type ReqName = fn(Edition, IsDotDotDot) -> bool;
31
32#[derive(#[automatically_derived]impl ::core::marker::Copy for IsDotDotDot { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for IsDotDotDot {
}
#[automatically_derived]impl ::core::clone::Clone for IsDotDotDot {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
IsDotDotDot {
}
#[automatically_derived]impl ::core::cmp::PartialEq for IsDotDotDot {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq)]
33pub(crate) enum IsDotDotDot {
34 Yes,
35 No,
36}
37
38#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for FnParseMode {
}
#[automatically_derived]impl ::core::clone::Clone for FnParseMode {
#[inline]
fn clone(&self) -> Self {
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)]
46pub(crate) struct FnParseMode {
47 pub(super) req_name: ReqName,
73 pub(super) context: FnContext,
76 pub(super) req_body: bool,
95 pub(super) allow_const_params: bool,
99}
100
101#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for FnContext {
}
#[automatically_derived]impl ::core::clone::Clone for FnContext {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for FnContext { }Copy, #[automatically_derived]impl ::core::marker::StructuralPartialEq for FnContext
{
}
#[automatically_derived]impl ::core::cmp::PartialEq for FnContext {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for FnContext { }Eq)]
104pub(crate) enum FnContext {
105 Free,
107 FunctionPtrType,
109 ParenthesizedArgumentList,
111 Trait,
113 Impl,
115}
116
117impl<'a> Parser<'a> {
119 pub(super) fn parse_fn(
121 &mut self,
122 attrs: &mut AttrVec,
123 fn_parse_mode: FnParseMode,
124 sig_lo: Span,
125 vis: &Visibility,
126 case: Case,
127 ) -> PResult<'a, (Ident, FnSig, Generics, Option<Box<FnContract>>, Option<Box<Block>>)> {
128 let fn_span = self.token.span;
129 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)
133 {
134 Ok(decl) => decl,
135 Err(old_err) => {
136 if self.token.is_keyword(kw::For) {
138 old_err.cancel();
139 return Err(self.dcx().create_err(diagnostics::FnTypoWithImpl { fn_span }));
140 } else {
141 return Err(old_err);
142 }
143 }
144 };
145
146 let decl = Box::new(decl);
147
148 let fn_params_end = self.prev_token.span.shrink_to_hi();
151
152 let contract = self.parse_contract()?;
153
154 generics.where_clause = self.parse_where_clause()?; let fn_params_end =
158 if generics.where_clause.has_where_token { Some(fn_params_end) } else { None };
159
160 let mut sig_hi = self.prev_token.span;
161 let body =
163 self.parse_fn_body(attrs, &ident, &mut sig_hi, fn_parse_mode.req_body, fn_params_end)?;
164 let fn_sig_span = sig_lo.to(sig_hi);
165 Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, contract, body))
166 }
167
168 fn error_fn_body_not_found(
170 &mut self,
171 ident_span: Span,
172 req_body: bool,
173 fn_params_end: Option<Span>,
174 ) -> PResult<'a, ErrorGuaranteed> {
175 let expected: &[_] =
176 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)] };
177 match self.expected_one_of_not_found(&[], expected) {
178 Ok(error_guaranteed) => Ok(error_guaranteed),
179 Err(mut err) => {
180 if self.token == token::CloseBrace {
181 err.span_label(ident_span, "while parsing this `fn`");
184 Ok(err.emit_err())
185 } else if self.token == token::RArrow
186 && let Some(fn_params_end) = fn_params_end
187 {
188 let fn_trait_span =
194 [sym::FnOnce, sym::FnMut, sym::Fn].into_iter().find_map(|symbol| {
195 if self.prev_token.is_ident_named(symbol) {
196 Some(self.prev_token.span)
197 } else {
198 None
199 }
200 });
201
202 let arrow_span = self.token.span;
207 let ty_span = match self.parse_ret_ty(
208 AllowPlus::Yes,
209 RecoverQPath::Yes,
210 RecoverReturnSign::Yes,
211 ) {
212 Ok(ty_span) => ty_span.span().shrink_to_hi(),
213 Err(parse_error) => {
214 parse_error.cancel();
215 return Err(err);
216 }
217 };
218 let ret_ty_span = arrow_span.to(ty_span);
219
220 if let Some(fn_trait_span) = fn_trait_span {
221 err.subdiagnostic(diagnostics::FnTraitMissingParen { span: fn_trait_span });
224 } else if let Ok(snippet) = self.psess.source_map().span_to_snippet(ret_ty_span)
225 {
226 err.primary_message(
230 "return type should be specified after the function parameters",
231 );
232 err.subdiagnostic(diagnostics::MisplacedReturnType {
233 fn_params_end,
234 snippet,
235 ret_ty_span,
236 });
237 }
238 Err(err)
239 } else {
240 Err(err)
241 }
242 }
243 }
244 }
245
246 fn parse_fn_body(
250 &mut self,
251 attrs: &mut AttrVec,
252 ident: &Ident,
253 sig_hi: &mut Span,
254 req_body: bool,
255 fn_params_end: Option<Span>,
256 ) -> PResult<'a, Option<Box<Block>>> {
257 let has_semi = if req_body {
258 self.token == TokenKind::Semi
259 } else {
260 self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Semi,
token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi))
262 };
263 let (inner_attrs, body) = if has_semi {
264 self.expect_semi()?;
266 *sig_hi = self.prev_token.span;
267 (AttrVec::new(), None)
268 } 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() {
269 let prev_in_fn_body = self.in_fn_body;
270 self.in_fn_body = true;
271 let res = self.parse_block_common(self.token.span, BlockCheckMode::Default, None).map(
272 |(attrs, mut body)| {
273 if let Some(guar) = self.fn_body_missing_semi_guar.take() {
274 body.stmts.push(self.mk_stmt(
275 body.span,
276 StmtKind::Expr(self.mk_expr(body.span, ExprKind::Err(guar))),
277 ));
278 }
279 (attrs, Some(body))
280 },
281 );
282 self.in_fn_body = prev_in_fn_body;
283 res?
284 } else if self.token == token::Eq {
285 self.bump(); let eq_sp = self.prev_token.span;
288 let _ = self.parse_expr()?;
289 self.expect_semi()?; let span = eq_sp.to(self.prev_token.span);
291 let guar = self.dcx().emit_err(diagnostics::FunctionBodyEqualsExpr {
292 span,
293 sugg: diagnostics::FunctionBodyEqualsExprSugg {
294 eq: eq_sp,
295 semi: self.prev_token.span,
296 },
297 });
298 (AttrVec::new(), Some(self.mk_block_err(span, guar)))
299 } else {
300 self.error_fn_body_not_found(ident.span, req_body, fn_params_end)?;
301 (AttrVec::new(), None)
302 };
303 attrs.extend(inner_attrs);
304 Ok(body)
305 }
306
307 pub(super) fn check_fn_front_matter(&mut self, check_pub: bool, case: Case) -> bool {
312 const ALL_QUALS: &[ExpKeywordPair] = &[
313 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Pub,
token_type: crate::parser::token_type::TokenType::KwPub,
}exp!(Pub),
314 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Gen,
token_type: crate::parser::token_type::TokenType::KwGen,
}exp!(Gen),
315 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Const,
token_type: crate::parser::token_type::TokenType::KwConst,
}exp!(Const),
316 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Async,
token_type: crate::parser::token_type::TokenType::KwAsync,
}exp!(Async),
317 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Unsafe,
token_type: crate::parser::token_type::TokenType::KwUnsafe,
}exp!(Unsafe),
318 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Safe,
token_type: crate::parser::token_type::TokenType::KwSafe,
}exp!(Safe),
319 crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Extern,
token_type: crate::parser::token_type::TokenType::KwExtern,
}exp!(Extern),
320 ];
321
322 let quals: &[_] = if check_pub {
327 ALL_QUALS
328 } else {
329 &[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)]
330 };
331 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))
334 && self.look_ahead(1, |t| {
335 t.is_keyword_case(kw::Fn, case)
337 || (
339 (
340 t.non_raw_ident().is_some_and(|i|
341 quals.iter().any(|exp| exp.kw == i.name)
342 && i.is_reserved()
344 )
345 || case == Case::Insensitive
346 && t.non_raw_ident().is_some_and(|i| quals.iter().any(|exp| {
347 exp.kw.as_str() == i.name.as_str().to_lowercase()
348 }))
349 )
350 && !self.is_unsafe_foreign_mod()
352 && !self.is_async_gen_block()
354 && !self.is_keyword_ahead(2, &[kw::Auto, kw::Trait, kw::Impl])
356 )
357 })
358 || 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)
360 && self.look_ahead(1, |t| t.can_begin_string_literal())
364 && (self.tree_look_ahead(2, |tt| {
365 match tt {
366 TokenTree::Token(t, _) => t.is_keyword_case(kw::Fn, case),
367 TokenTree::Delimited(..) => false,
368 }
369 }) == Some(true) ||
370 (self.may_recover()
375 && self.tree_look_ahead(2, |tt| {
376 match tt {
377 TokenTree::Token(t, _) =>
378 ALL_QUALS.iter().any(|exp| {
379 t.is_keyword(exp.kw)
380 }),
381 TokenTree::Delimited(..) => false,
382 }
383 }) == Some(true)
384 && self.tree_look_ahead(3, |tt| {
385 match tt {
386 TokenTree::Token(t, _) => {
387 t.is_keyword_case(kw::Fn, case) ||
388 ALL_QUALS.iter().any(|exp| {
389 t.is_keyword(exp.kw)
390 })
391 },
392 TokenTree::Delimited(..) => false,
393 }
394 }) == Some(true)
395 )
396 )
397 }
398
399 pub(super) fn parse_fn_front_matter(
414 &mut self,
415 orig_vis: &Visibility,
416 case: Case,
417 parsing_mode: FrontMatterParsingMode,
418 ) -> PResult<'a, FnHeader> {
419 let sp_start = self.token.span;
420 let constness = self.parse_constness(case);
421 if parsing_mode == FrontMatterParsingMode::FunctionPtrType
422 && let Const::Yes(const_span) = constness
423 {
424 self.dcx().emit_err(FnPointerCannotBeConst {
425 span: const_span,
426 suggestion: const_span.until(self.token.span),
427 });
428 }
429
430 let async_start_sp = self.token.span;
431 let coroutine_marker = self.parse_coroutine_marker(case);
432 if parsing_mode == FrontMatterParsingMode::FunctionPtrType
433 && let Some(coroutine_marker) = coroutine_marker
434 && coroutine_marker.kind == CoroutineKind::Async
435 {
436 self.dcx().emit_err(FnPointerCannotBeAsync {
437 span: coroutine_marker.span,
438 suggestion: coroutine_marker.span.until(self.token.span),
439 });
440 }
441 let unsafe_start_sp = self.token.span;
444 let safety = self.parse_safety(case);
445
446 let ext_start_sp = self.token.span;
447 let ext = self.parse_extern(case);
448
449 if let Some(coroutine_marker) = coroutine_marker
450 && let CoroutineKind::Async = coroutine_marker.kind
451 && coroutine_marker.span.is_rust_2015()
452 {
453 self.dcx().emit_err(diagnostics::AsyncFnIn2015 {
454 span: coroutine_marker.span,
455 help: diagnostics::HelpUseLatestEdition::new(),
456 });
457 }
458
459 if let Some(coroutine_marker) = coroutine_marker
460 && coroutine_marker.kind.is_gen()
461 {
462 self.psess.gated_spans.gate(sym::gen_blocks, coroutine_marker.span);
463 }
464
465 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) {
466 match self.expect_one_of(&[], &[]) {
470 Ok(Recovered::Yes(_)) => {}
471 Ok(Recovered::No) => ::core::panicking::unreachable_default_msg()unreachable!(),
472 Err(mut err) => {
473 enum WrongKw {
475 Duplicated(Span),
476 Misplaced(Span),
477 MisplacedDisallowedQualifier,
482 }
483
484 let mut recover_constness = constness;
486 let mut recover_coroutine_marker = coroutine_marker;
487 let mut recover_safety = safety;
488 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)) {
491 match constness {
492 Const::Yes(sp) => Some(WrongKw::Duplicated(sp)),
493 Const::No => {
494 recover_constness = Const::Yes(self.token.span);
495 match parsing_mode {
496 FrontMatterParsingMode::Function => {
497 Some(WrongKw::Misplaced(async_start_sp))
498 }
499 FrontMatterParsingMode::FunctionPtrType => {
500 self.dcx().emit_err(FnPointerCannotBeConst {
501 span: self.token.span,
502 suggestion: self
503 .token
504 .span
505 .with_lo(self.prev_token.span.hi()),
506 });
507 Some(WrongKw::MisplacedDisallowedQualifier)
508 }
509 }
510 }
511 }
512 } 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)) {
513 match coroutine_marker {
514 Some(CoroutineMarker {
515 kind: CoroutineKind::Async | CoroutineKind::AsyncGen,
516 span,
517 ..
518 }) => Some(WrongKw::Duplicated(span)),
519 Some(CoroutineMarker { kind: CoroutineKind::Gen, .. }) => {
520 recover_coroutine_marker = Some(CoroutineMarker::new(
521 CoroutineKind::AsyncGen,
522 self.token.span,
523 ));
524 Some(WrongKw::Misplaced(unsafe_start_sp))
526 }
527 None => {
528 recover_coroutine_marker = Some(CoroutineMarker::new(
529 CoroutineKind::Async,
530 self.token.span,
531 ));
532 match parsing_mode {
533 FrontMatterParsingMode::Function => {
534 Some(WrongKw::Misplaced(async_start_sp))
535 }
536 FrontMatterParsingMode::FunctionPtrType => {
537 self.dcx().emit_err(FnPointerCannotBeAsync {
538 span: self.token.span,
539 suggestion: self
540 .token
541 .span
542 .with_lo(self.prev_token.span.hi()),
543 });
544 Some(WrongKw::MisplacedDisallowedQualifier)
545 }
546 }
547 }
548 }
549 } 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)) {
550 match safety {
551 Safety::Unsafe(sp) => Some(WrongKw::Duplicated(sp)),
552 Safety::Safe(sp) => {
553 recover_safety = Safety::Unsafe(self.token.span);
554 Some(WrongKw::Misplaced(sp))
555 }
556 Safety::Default => {
557 recover_safety = Safety::Unsafe(self.token.span);
558 Some(WrongKw::Misplaced(ext_start_sp))
559 }
560 }
561 } 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)) {
562 match safety {
563 Safety::Safe(sp) => Some(WrongKw::Duplicated(sp)),
564 Safety::Unsafe(sp) => {
565 recover_safety = Safety::Safe(self.token.span);
566 Some(WrongKw::Misplaced(sp))
567 }
568 Safety::Default => {
569 recover_safety = Safety::Safe(self.token.span);
570 Some(WrongKw::Misplaced(ext_start_sp))
571 }
572 }
573 } else {
574 None
575 };
576
577 if let Some(WrongKw::Duplicated(original_sp)) = wrong_kw {
579 let original_kw = self
580 .span_to_snippet(original_sp)
581 .expect("Span extracted directly from keyword should always work");
582
583 err.span_suggestion_verbose(
584 self.token_uninterpolated_span(),
585 ::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"),
586 "",
587 Applicability::MachineApplicable,
588 )
589 .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"));
590 }
591 else if let Some(WrongKw::Misplaced(correct_pos_sp)) = wrong_kw {
593 let correct_pos_sp = correct_pos_sp.to(self.prev_token.span);
594 if let Ok(current_qual) = self.span_to_snippet(correct_pos_sp) {
595 let misplaced_qual_sp = self.token_uninterpolated_span();
596 let misplaced_qual = self.span_to_snippet(misplaced_qual_sp).unwrap();
597
598 err.span_suggestion_verbose(
599 correct_pos_sp.to(misplaced_qual_sp),
600 ::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}`"),
601 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} {1}", misplaced_qual,
current_qual))
})format!("{misplaced_qual} {current_qual}"),
602 Applicability::MachineApplicable,
603 ).note("keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`");
604 }
605 }
606 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)) {
608 let sp = sp_start.to(self.prev_token.span);
609 if let Ok(snippet) = self.span_to_snippet(sp) {
610 let current_vis = match self.parse_visibility(FollowedByType::No) {
611 Ok(v) => v,
612 Err(d) => {
613 d.cancel();
614 return Err(err);
615 }
616 };
617 let vs = pprust::vis_to_string(¤t_vis);
618 let vs = vs.trim_end();
619
620 if #[allow(non_exhaustive_omitted_patterns)] match orig_vis.kind {
VisibilityKind::Inherited => true,
_ => false,
}matches!(orig_vis.kind, VisibilityKind::Inherited) {
622 err.span_suggestion_verbose(
623 sp_start.to(self.prev_token.span),
624 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("visibility `{0}` must come before `{1}`",
vs, snippet))
})format!("visibility `{vs}` must come before `{snippet}`"),
625 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} {1}", vs, snippet))
})format!("{vs} {snippet}"),
626 Applicability::MachineApplicable,
627 );
628 }
629 else {
631 err.span_suggestion_verbose(
632 current_vis.span,
633 "there is already a visibility modifier, remove one",
634 "",
635 Applicability::MachineApplicable,
636 )
637 .span_note(orig_vis.span, "explicit visibility first seen here");
638 }
639 }
640 }
641
642 if let Some(wrong_kw) = wrong_kw
645 && self.may_recover()
646 && self.look_ahead(1, |tok| tok.is_keyword_case(kw::Fn, case))
647 {
648 self.bump();
650 self.bump();
651 if #[allow(non_exhaustive_omitted_patterns)] match wrong_kw {
WrongKw::MisplacedDisallowedQualifier => true,
_ => false,
}matches!(wrong_kw, WrongKw::MisplacedDisallowedQualifier) {
654 err.cancel();
655 } else {
656 err.emit();
657 }
658 return Ok(FnHeader {
659 constness: recover_constness,
660 safety: recover_safety,
661 coroutine_marker: recover_coroutine_marker,
662 ext,
663 });
664 }
665
666 return Err(err);
667 }
668 }
669 }
670
671 Ok(FnHeader { constness, safety, coroutine_marker, ext })
672 }
673
674 pub(super) fn parse_fn_decl(
676 &mut self,
677 fn_parse_mode: &FnParseMode,
678 ret_allow_plus: AllowPlus,
679 recover_return_sign: RecoverReturnSign,
680 ) -> PResult<'a, FnDecl> {
681 Ok(FnDecl {
682 inputs: self.parse_fn_params(fn_parse_mode)?,
683 output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, recover_return_sign)?,
684 })
685 }
686
687 pub(super) fn parse_fn_params(
689 &mut self,
690 fn_parse_mode: &FnParseMode,
691 ) -> PResult<'a, ThinVec<Param>> {
692 let mut first_param = true;
693 if self.token != TokenKind::OpenParen
695 && !self.token.is_keyword(kw::For)
697 {
698 self.dcx().emit_err(diagnostics::MissingFnParams {
700 span: self.prev_token.span.shrink_to_hi(),
701 });
702 return Ok(ThinVec::new());
703 }
704
705 let (mut params, _) = self.parse_paren_comma_seq(|p| {
706 p.recover_vcs_conflict_marker();
707 let snapshot = p.create_snapshot_for_diagnostic();
708 let param = p.parse_param_general(fn_parse_mode, first_param).or_else(|e| {
709 let guar = e.emit_err();
710 let lo = if let TokenKind::OpenParen = p.prev_token.kind {
714 p.prev_token.span.shrink_to_hi()
715 } else {
716 p.prev_token.span
717 };
718 p.restore_snapshot(snapshot);
719 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)]);
721 Ok(dummy_arg(Ident::new(sym::dummy, lo.to(p.prev_token.span)), guar))
723 });
724 first_param = false;
726 param
727 })?;
728 self.deduplicate_recovered_params_names(&mut params);
730 Ok(params)
731 }
732
733 pub(super) fn parse_param_general(
738 &mut self,
739 fn_parse_mode: &FnParseMode,
740 first_param: bool,
741 ) -> PResult<'a, Param> {
742 let lo = self.token.span;
743 let attrs = self.parse_outer_attributes()?;
744 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
745 if let Some(mut param) = this.parse_self_param()? {
747 param.attrs = attrs;
748 let res = if first_param { Ok(param) } else { this.recover_bad_self_param(param) };
749 return Ok((res?, Trailing::No, UsePreAttrPos::No));
750 }
751
752 let is_dot_dot_dot = if this.token.kind == token::DotDotDot {
753 IsDotDotDot::Yes
754 } else {
755 IsDotDotDot::No
756 };
757 let is_name_required = (fn_parse_mode.req_name)(
758 this.token.span.with_neighbor(this.prev_token.span).edition(),
759 is_dot_dot_dot,
760 );
761 let is_name_required = if is_name_required && is_dot_dot_dot == IsDotDotDot::Yes {
762 this.psess.buffer_lint(
763 VARARGS_WITHOUT_PATTERN,
764 this.token.span,
765 ast::CRATE_NODE_ID,
766 diagnostics::VarargsWithoutPattern { span: this.token.span },
767 );
768 false
769 } else {
770 is_name_required
771 };
772
773 let mut is_const = false;
774 if fn_parse_mode.allow_const_params
775 && this.token.is_keyword(kw::Const)
776 && this.look_ahead(1, |token| token.is_non_reserved_ident())
777 && this.look_ahead(2, |token| *token == token::Colon)
778 {
779 this.bump();
780 let span = this.prev_token.span;
781 is_const = true;
782 this.psess.gated_spans.gate(sym::function_arg_const_generics, span);
783 }
784
785 let (pat, ty) = if is_name_required || this.is_named_param() {
786 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/1c3a6506966e21845b31de0b075d2527660db132/compiler/rustc_parse/src/parser/function.rs:786",
"rustc_parse::parser::function", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/1c3a6506966e21845b31de0b075d2527660db132/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 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);
787 let (pat, colon) = this.parse_fn_param_pat_colon()?;
788 if !colon {
789 let mut err = this.unexpected().unwrap_err();
790 let pat_span = pat.span;
791 return if let Some(ident) = this.parameter_without_type(
792 &mut err,
793 pat,
794 is_name_required,
795 first_param,
796 fn_parse_mode,
797 ) {
798 let guar = err.emit_err();
799 let mut arg = dummy_arg(ident, guar);
800 arg.span = pat_span;
801 Ok((arg, Trailing::No, UsePreAttrPos::No))
802 } else {
803 Err(err)
804 };
805 }
806 let ty = if is_const { this.parse_ty() } else { this.parse_ty_for_param() };
807
808 (pat, ty?)
809 } else {
810 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/1c3a6506966e21845b31de0b075d2527660db132/compiler/rustc_parse/src/parser/function.rs:810",
"rustc_parse::parser::function", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/1c3a6506966e21845b31de0b075d2527660db132/compiler/rustc_parse/src/parser/function.rs"),
::tracing_core::__macro_support::Option::Some(810u32),
::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");
811 let parser_snapshot_before_ty = this.create_snapshot_for_diagnostic();
812 let mut ty = this.parse_ty_for_param();
813
814 if let Ok(t) = &ty {
815 if let TyKind::Path(_, Path { segments, .. }) = &t.kind
817 && let Some(segment) = segments.last()
818 && let Some(guar) =
819 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)])
820 {
821 return Ok((
822 dummy_arg(segment.ident, guar),
823 Trailing::No,
824 UsePreAttrPos::No,
825 ));
826 }
827
828 if this.token != token::Comma && this.token != token::CloseParen {
829 ty = this.unexpected_any();
832 }
833 }
834 match ty {
835 Ok(ty) => {
836 let pat = this.mk_pat(ty.span, PatKind::Missing);
837 (Box::new(pat), ty)
838 }
839 Err(err) if this.token == token::DotDotDot => return Err(err),
841 Err(err) if this.unmatched_angle_bracket_count > 0 => return Err(err),
842 Err(err) => {
843 this.restore_snapshot(parser_snapshot_before_ty);
845 match this.recover_arg_parse(fn_parse_mode.context) {
846 Ok(res) => {
847 err.cancel();
849 res
850 }
851 Err(new_err) => {
852 new_err.cancel();
854 return Err(err);
855 }
856 }
857 }
858 }
859 };
860
861 let span = lo.to(this.prev_token.span);
862
863 Ok((
864 Param {
865 attrs,
866 id: ast::DUMMY_NODE_ID,
867 is_placeholder: false,
868 pat,
869 span,
870 ty,
871 has_const_keyword: is_const,
872 },
873 Trailing::No,
874 UsePreAttrPos::No,
875 ))
876 })
877 }
878
879 fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
881 let expect_self_ident = |this: &mut Self| {
883 let ident = this.token.non_raw_ident().unwrap();
884 this.bump();
885 ident
886 };
887 let is_lifetime = |this: &Self, n| this.look_ahead(n, |t| t.is_lifetime());
889 let is_isolated_self = |this: &Self, n| {
891 this.is_keyword_ahead(n, &[kw::SelfLower])
892 && this.look_ahead(n + 1, |t| t != &token::PathSep)
893 };
894 let is_isolated_pin_const_self = |this: &Self, n| {
896 this.is_keyword_ahead(n, &[kw::Pin])
897 && this.is_keyword_ahead(n + 1, &[kw::Const])
898 && is_isolated_self(this, n + 2)
899 };
900 let is_isolated_mut_self =
902 |this: &Self, n| this.is_keyword_ahead(n, &[kw::Mut]) && is_isolated_self(this, n + 1);
903 let is_isolated_pin_mut_self = |this: &Self, n| {
905 this.is_keyword_ahead(n, &[kw::Pin]) && is_isolated_mut_self(this, n + 1)
906 };
907 let parse_self_possibly_typed = |this: &mut Self, m| {
909 let eself_ident = expect_self_ident(this);
910 let eself_hi = this.prev_token.span;
911 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)) {
912 SelfKind::Explicit(this.parse_ty()?, m)
913 } else {
914 SelfKind::Value(m)
915 };
916 Ok((eself, eself_ident, eself_hi))
917 };
918 let expect_self_ident_not_typed =
919 |this: &mut Self, modifier: &SelfKind, modifier_span: Span| {
920 let eself_ident = expect_self_ident(this);
921
922 if this.may_recover() && this.eat_noexpect(&token::Colon) {
924 let snap = this.create_snapshot_for_diagnostic();
925 match this.parse_ty() {
926 Ok(ty) => {
927 this.dcx().emit_err(diagnostics::IncorrectTypeOnSelf {
928 span: ty.span,
929 move_self_modifier: diagnostics::MoveSelfModifier {
930 removal_span: modifier_span,
931 insertion_span: ty.span.shrink_to_lo(),
932 modifier: modifier.to_ref_suggestion(),
933 },
934 });
935 }
936 Err(diag) => {
937 diag.cancel();
938 this.restore_snapshot(snap);
939 }
940 }
941 }
942 eself_ident
943 };
944 let recover_self_ptr = |this: &mut Self| {
946 this.dcx().emit_err(diagnostics::SelfArgumentPointer { span: this.token.span });
947
948 Ok((SelfKind::Value(Mutability::Not), expect_self_ident(this), this.prev_token.span))
949 };
950
951 let eself_lo = self.token.span;
955 let (eself, eself_ident, eself_hi) = match self.token.uninterpolate().kind {
956 token::And => {
957 let has_lifetime = is_lifetime(self, 1);
958 let skip_lifetime_count = has_lifetime as usize;
959 let eself = if is_isolated_self(self, skip_lifetime_count + 1) {
960 self.bump(); let lifetime = has_lifetime.then(|| self.expect_lifetime());
963 SelfKind::Region(lifetime, Mutability::Not)
964 } else if is_isolated_mut_self(self, skip_lifetime_count + 1) {
965 self.bump(); let lifetime = has_lifetime.then(|| self.expect_lifetime());
968 self.bump(); SelfKind::Region(lifetime, Mutability::Mut)
970 } else if is_isolated_pin_const_self(self, skip_lifetime_count + 1) {
971 self.bump(); let lifetime = has_lifetime.then(|| self.expect_lifetime());
974 self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
975 self.bump(); self.bump(); SelfKind::Pinned(lifetime, Mutability::Not)
978 } else if is_isolated_pin_mut_self(self, skip_lifetime_count + 1) {
979 self.bump(); let lifetime = has_lifetime.then(|| self.expect_lifetime());
982 self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
983 self.bump(); self.bump(); SelfKind::Pinned(lifetime, Mutability::Mut)
986 } else {
987 return Ok(None);
989 };
990 let hi = self.token.span;
991 let self_ident = expect_self_ident_not_typed(self, &eself, eself_lo.until(hi));
992 (eself, self_ident, hi)
993 }
994 token::Star if is_isolated_self(self, 1) => {
996 self.bump();
997 recover_self_ptr(self)?
998 }
999 token::Star
1001 if self.look_ahead(1, |t| t.is_mutability()) && is_isolated_self(self, 2) =>
1002 {
1003 self.bump();
1004 self.bump();
1005 recover_self_ptr(self)?
1006 }
1007 token::Ident(..) if is_isolated_self(self, 0) => {
1009 parse_self_possibly_typed(self, Mutability::Not)?
1010 }
1011 token::Ident(..) if is_isolated_mut_self(self, 0) => {
1013 self.bump();
1014 parse_self_possibly_typed(self, Mutability::Mut)?
1015 }
1016 _ => return Ok(None),
1017 };
1018
1019 let eself = respan(eself_lo.to(eself_hi), eself);
1020 Ok(Some(Param::from_self(AttrVec::default(), eself, eself_ident)))
1021 }
1022
1023 fn is_named_param(&self) -> bool {
1024 let offset = match &self.token.kind {
1025 token::OpenInvisible(origin) => match origin {
1026 InvisibleOrigin::MetaVar(MetaVarKind::Pat(_)) => {
1027 return self.check_noexpect_past_close_delim(&token::Colon);
1028 }
1029 _ => 0,
1030 },
1031 token::And | token::AndAnd => 1,
1032 _ if self.token.is_keyword(kw::Mut) => 1,
1033 _ => 0,
1034 };
1035
1036 self.look_ahead(offset, |t| t.is_ident())
1037 && self.look_ahead(offset + 1, |t| t == &token::Colon)
1038 }
1039
1040 pub(super) fn recover_self_param(&mut self) -> bool {
1041 #[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!(
1042 self.parse_outer_attributes()
1043 .and_then(|_| self.parse_self_param())
1044 .map_err(|e| e.cancel()),
1045 Ok(Some(_))
1046 )
1047 }
1048}
1049
1050#[derive(#[automatically_derived]impl ::core::marker::Copy for FrontMatterParsingMode {
}Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for FrontMatterParsingMode {
}
#[automatically_derived]impl ::core::clone::Clone for FrontMatterParsingMode {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
FrontMatterParsingMode {
}
#[automatically_derived]impl ::core::cmp::PartialEq for FrontMatterParsingMode
{
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for FrontMatterParsingMode { }Eq)]
1051pub(crate) enum FrontMatterParsingMode {
1052 Function,
1054 FunctionPtrType,
1057}