Skip to content

Commit

Permalink
Recover from &dyn mut ... parse errors
Browse files Browse the repository at this point in the history
  • Loading branch information
FabianWolff committed Jul 2, 2021
1 parent ce331ee commit c692896
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 1 deletion.
22 changes: 21 additions & 1 deletion compiler/rustc_parse/src/parser/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ impl<'a> Parser<'a> {
let and_span = self.prev_token.span;
let mut opt_lifetime =
if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
let mutbl = self.parse_mutability();
let mut mutbl = self.parse_mutability();
if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() {
// A lifetime is invalid here: it would be part of a bare trait bound, which requires
// it to be followed by a plus, but we disallow plus in the pointee type.
Expand All @@ -417,6 +417,26 @@ impl<'a> Parser<'a> {

opt_lifetime = Some(self.expect_lifetime());
}
} else if self.token.is_keyword(kw::Dyn)
&& mutbl == Mutability::Not
&& self.look_ahead(1, |t| t.is_keyword(kw::Mut))
{
// We have `&dyn mut ...`, which is invalid and should be `&mut dyn ...`.
let span = and_span.to(self.look_ahead(1, |t| t.span));
let mut err = self.struct_span_err(span, "`mut` must precede `dyn`");
err.span_suggestion(
span,
"place `mut` before `dyn`",
"&mut dyn".to_string(),
Applicability::MachineApplicable,
);
err.emit();

// Recovery
mutbl = Mutability::Mut;
let (dyn_tok, dyn_tok_sp) = (self.token.clone(), self.token_spacing);
self.bump();
self.bump_with((dyn_tok, dyn_tok_sp));
}
let ty = self.parse_ty_no_plus()?;
Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl }))
Expand Down
9 changes: 9 additions & 0 deletions src/test/ui/parser/recover-ref-dyn-mut.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Test that the parser detects `&dyn mut`, offers a help message, and
// recovers.

fn main() {
let r: &dyn mut Trait;
//~^ ERROR: `mut` must precede `dyn`
//~| HELP: place `mut` before `dyn`
//~| ERROR: cannot find trait `Trait` in this scope [E0405]
}
15 changes: 15 additions & 0 deletions src/test/ui/parser/recover-ref-dyn-mut.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error: `mut` must precede `dyn`
--> $DIR/recover-ref-dyn-mut.rs:5:12
|
LL | let r: &dyn mut Trait;
| ^^^^^^^^ help: place `mut` before `dyn`: `&mut dyn`

error[E0405]: cannot find trait `Trait` in this scope
--> $DIR/recover-ref-dyn-mut.rs:5:21
|
LL | let r: &dyn mut Trait;
| ^^^^^ not found in this scope

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0405`.

0 comments on commit c692896

Please sign in to comment.