Skip to content

Commit

Permalink
Rollup merge of #97172 - SparrowLii:unsafe_extern, r=compiler-errors
Browse files Browse the repository at this point in the history
Optimize the diagnostic generation for `extern unsafe`

This PR does the following about diagnostic generation when parsing foreign mod:
1. Fixes the FIXME about avoiding depending on the error message text.
2. Continue parsing when `unsafe` is followed by `{` (just like `unsafe extern {...}`).
3. Add test case.
  • Loading branch information
compiler-errors authored May 30, 2022
2 parents 3c0b9d5 + 0be2ca9 commit 22da719
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 32 deletions.
41 changes: 15 additions & 26 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -996,35 +996,24 @@ impl<'a> Parser<'a> {
fn parse_item_foreign_mod(
&mut self,
attrs: &mut Vec<Attribute>,
unsafety: Unsafe,
mut unsafety: Unsafe,
) -> PResult<'a, ItemInfo> {
let sp_start = self.prev_token.span;
let abi = self.parse_abi(); // ABI?
match self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No)) {
Ok(items) => {
let module = ast::ForeignMod { unsafety, abi, items };
Ok((Ident::empty(), ItemKind::ForeignMod(module)))
}
Err(mut err) => {
let current_qual_sp = self.prev_token.span;
let current_qual_sp = current_qual_sp.to(sp_start);
if let Ok(current_qual) = self.span_to_snippet(current_qual_sp) {
// FIXME(davidtwco): avoid depending on the error message text
if err.message[0].0.expect_str() == "expected `{`, found keyword `unsafe`" {
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 `pub`, `default`, `const`, `async`, `unsafe`, `extern`");
}
}
Err(err)
}
if unsafety == Unsafe::No
&& self.token.is_keyword(kw::Unsafe)
&& self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Brace))
{
let mut err = self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err();
err.emit();
unsafety = Unsafe::Yes(self.token.span);
self.eat_keyword(kw::Unsafe);
}
let module = ast::ForeignMod {
unsafety,
abi,
items: self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?,
};
Ok((Ident::empty(), ItemKind::ForeignMod(module)))
}

/// Parses a foreign item (one in an `extern { ... }` block).
Expand Down
7 changes: 1 addition & 6 deletions src/test/ui/parser/issues/issue-19398.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@ error: expected `{`, found keyword `unsafe`
LL | trait T {
| - while parsing this item list starting here
LL | extern "Rust" unsafe fn foo();
| --------------^^^^^^
| | |
| | expected `{`
| help: `unsafe` must come before `extern "Rust"`: `unsafe extern "Rust"`
| ^^^^^^ expected `{`
LL |
LL | }
| - the item list ends here
|
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

error: aborting due to previous error

8 changes: 8 additions & 0 deletions src/test/ui/parser/unsafe-foreign-mod-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
extern "C" unsafe {
//~^ ERROR expected `{`, found keyword `unsafe`
//~| ERROR extern block cannot be declared unsafe
unsafe fn foo();
//~^ ERROR functions in `extern` blocks cannot have qualifiers
}

fn main() {}
28 changes: 28 additions & 0 deletions src/test/ui/parser/unsafe-foreign-mod-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
error: expected `{`, found keyword `unsafe`
--> $DIR/unsafe-foreign-mod-2.rs:1:12
|
LL | extern "C" unsafe {
| ^^^^^^ expected `{`

error: extern block cannot be declared unsafe
--> $DIR/unsafe-foreign-mod-2.rs:1:12
|
LL | extern "C" unsafe {
| ^^^^^^

error: functions in `extern` blocks cannot have qualifiers
--> $DIR/unsafe-foreign-mod-2.rs:4:15
|
LL | extern "C" unsafe {
| ----------------- in this `extern` block
...
LL | unsafe fn foo();
| ^^^
|
help: remove the qualifiers
|
LL | fn foo();
| ~~

error: aborting due to 3 previous errors

0 comments on commit 22da719

Please sign in to comment.