diff options
| author | Alexis Bourget <alexis.bourget@gmail.com> | 2021-08-02 11:10:19 +0200 |
|---|---|---|
| committer | Alexis Bourget <alexis.bourget@gmail.com> | 2021-08-02 11:10:19 +0200 |
| commit | 690cbb79b396fa327b2381ab5e8fb22702623df5 (patch) | |
| tree | eb4ed7058377657c914c6bf238e3deda7c4a59bd /compiler/rustc_parse | |
| parent | f381e77d3590bc36f09b0d48cffb504f92febf5e (diff) | |
| download | rust-690cbb79b396fa327b2381ab5e8fb22702623df5.tar.gz rust-690cbb79b396fa327b2381ab5e8fb22702623df5.zip | |
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.
Diffstat (limited to 'compiler/rustc_parse')
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 35 |
1 files changed, 34 insertions, 1 deletions
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) { |
