Skip to content

Commit c692896

Browse files
committed
Recover from &dyn mut ... parse errors
1 parent ce331ee commit c692896

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed

compiler/rustc_parse/src/parser/ty.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ impl<'a> Parser<'a> {
393393
let and_span = self.prev_token.span;
394394
let mut opt_lifetime =
395395
if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
396-
let mutbl = self.parse_mutability();
396+
let mut mutbl = self.parse_mutability();
397397
if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() {
398398
// A lifetime is invalid here: it would be part of a bare trait bound, which requires
399399
// it to be followed by a plus, but we disallow plus in the pointee type.
@@ -417,6 +417,26 @@ impl<'a> Parser<'a> {
417417

418418
opt_lifetime = Some(self.expect_lifetime());
419419
}
420+
} else if self.token.is_keyword(kw::Dyn)
421+
&& mutbl == Mutability::Not
422+
&& self.look_ahead(1, |t| t.is_keyword(kw::Mut))
423+
{
424+
// We have `&dyn mut ...`, which is invalid and should be `&mut dyn ...`.
425+
let span = and_span.to(self.look_ahead(1, |t| t.span));
426+
let mut err = self.struct_span_err(span, "`mut` must precede `dyn`");
427+
err.span_suggestion(
428+
span,
429+
"place `mut` before `dyn`",
430+
"&mut dyn".to_string(),
431+
Applicability::MachineApplicable,
432+
);
433+
err.emit();
434+
435+
// Recovery
436+
mutbl = Mutability::Mut;
437+
let (dyn_tok, dyn_tok_sp) = (self.token.clone(), self.token_spacing);
438+
self.bump();
439+
self.bump_with((dyn_tok, dyn_tok_sp));
420440
}
421441
let ty = self.parse_ty_no_plus()?;
422442
Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl }))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Test that the parser detects `&dyn mut`, offers a help message, and
2+
// recovers.
3+
4+
fn main() {
5+
let r: &dyn mut Trait;
6+
//~^ ERROR: `mut` must precede `dyn`
7+
//~| HELP: place `mut` before `dyn`
8+
//~| ERROR: cannot find trait `Trait` in this scope [E0405]
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: `mut` must precede `dyn`
2+
--> $DIR/recover-ref-dyn-mut.rs:5:12
3+
|
4+
LL | let r: &dyn mut Trait;
5+
| ^^^^^^^^ help: place `mut` before `dyn`: `&mut dyn`
6+
7+
error[E0405]: cannot find trait `Trait` in this scope
8+
--> $DIR/recover-ref-dyn-mut.rs:5:21
9+
|
10+
LL | let r: &dyn mut Trait;
11+
| ^^^^^ not found in this scope
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0405`.

0 commit comments

Comments
 (0)