From 690cbb79b396fa327b2381ab5e8fb22702623df5 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Mon, 2 Aug 2021 11:10:19 +0200 Subject: Better message for invalid keyword placement in fn After this commit, `unsafe async fn ...` now suggests the `async unsafe` fix instead of misunderstanding the issue. This is not perfect for repeated keywords (`const async const`) and for keywords that are misplaced after `extern "some abi"` because of the way `check_fn_font_matter` works, but changing it breaks so many tests and diagnostics it has been judged too high a cost for this PR. --- compiler/rustc_parse/src/parser/item.rs | 35 ++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'compiler/rustc_parse/src') diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 2ce63d011f4..673caf35ea6 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1771,8 +1771,14 @@ impl<'a> Parser<'a> { pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { let sp_start = self.token.span; let constness = self.parse_constness(); + + let async_start_sp = self.token.span; let asyncness = self.parse_asyncness(); + + let unsafe_start_sp = self.token.span; let unsafety = self.parse_unsafety(); + + let ext_start_sp = self.token.span; let ext = self.parse_extern(); if let Async::Yes { span, .. } = asyncness { @@ -1787,8 +1793,35 @@ impl<'a> Parser<'a> { Ok(true) => {} Ok(false) => unreachable!(), Err(mut err) => { + // Qualifier keywords ordering check + + // This will allow the machine fix to directly place the keyword in the correct place + let current_qual_sp = if self.check_keyword(kw::Const) { + Some(async_start_sp) + } else if self.check_keyword(kw::Async) { + Some(unsafe_start_sp) + } else if self.check_keyword(kw::Unsafe) { + Some(ext_start_sp) + } else { + None + }; + + if let Some(current_qual_sp) = current_qual_sp { + let current_qual_sp = current_qual_sp.to(self.prev_token.span); + if let Ok(current_qual) = self.span_to_snippet(current_qual_sp) { + let invalid_qual_sp = self.token.uninterpolated_span(); + let invalid_qual = self.span_to_snippet(invalid_qual_sp).unwrap(); + + err.span_suggestion( + current_qual_sp.to(invalid_qual_sp), + &format!("`{}` must come before `{}`", invalid_qual, current_qual), + format!("{} {}", invalid_qual, current_qual), + Applicability::MachineApplicable, + ).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`"); + } + } // Recover incorrect visibility order such as `async pub`. - if self.check_keyword(kw::Pub) { + else if self.check_keyword(kw::Pub) { let sp = sp_start.to(self.prev_token.span); if let Ok(snippet) = self.span_to_snippet(sp) { let vis = match self.parse_visibility(FollowedByType::No) { -- cgit 1.4.1-3-g733a5