From 4de9a53d98533868dfa209bfb3604bba92d5e7b1 Mon Sep 17 00:00:00 2001 From: SNCPlay42 Date: Sun, 21 Jun 2020 21:37:17 +0100 Subject: [PATCH] improve diagnostics for lifetime after `&mut` --- compiler/rustc_parse/src/parser/ty.rs | 28 +++++++++- .../parser/issue-73568-lifetime-after-mut.rs | 21 ++++++++ .../issue-73568-lifetime-after-mut.stderr | 53 +++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/parser/issue-73568-lifetime-after-mut.rs create mode 100644 src/test/ui/parser/issue-73568-lifetime-after-mut.stderr diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 259764a317d..fc4c62ccbd9 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -276,8 +276,34 @@ impl<'a> Parser<'a> { } fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { - let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; + 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(); + 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. + // So we can handle this case as an error here, and suggest `'a mut`. + // If there *is* a plus next though, handling the error later provides better suggestions + // (like adding parentheses) + if !self.look_ahead(1, |t| t.is_like_plus()) { + let lifetime_span = self.token.span; + let span = and_span.to(lifetime_span); + + let mut err = self.struct_span_err(span, "lifetime must precede `mut`"); + if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) { + err.span_suggestion( + span, + "place the lifetime before `mut`", + format!("&{} mut", lifetime_src), + Applicability::MaybeIncorrect, + ); + } + err.emit(); + + opt_lifetime = Some(self.expect_lifetime()); + } + } let ty = self.parse_ty_no_plus()?; Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl })) } diff --git a/src/test/ui/parser/issue-73568-lifetime-after-mut.rs b/src/test/ui/parser/issue-73568-lifetime-after-mut.rs new file mode 100644 index 00000000000..0b10a5f6f4e --- /dev/null +++ b/src/test/ui/parser/issue-73568-lifetime-after-mut.rs @@ -0,0 +1,21 @@ +#![crate_type="lib"] +fn x<'a>(x: &mut 'a i32){} //~ ERROR lifetime must precede `mut` + +macro_rules! mac { + ($lt:lifetime) => { + fn w<$lt>(w: &mut $lt i32) {} + //~^ ERROR lifetime must precede `mut` + } +} + +mac!('a); + +// avoid false positives +fn y<'a>(y: &mut 'a + Send) { + //~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a` + //~| WARNING trait objects without an explicit `dyn` are deprecated + //~| ERROR at least one trait is required for an object type + let z = y as &mut 'a + Send; + //~^ ERROR expected value, found trait `Send` + //~| WARNING trait objects without an explicit `dyn` are deprecated +} diff --git a/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr b/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr new file mode 100644 index 00000000000..abb64f7e490 --- /dev/null +++ b/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr @@ -0,0 +1,53 @@ +error: lifetime must precede `mut` + --> $DIR/issue-73568-lifetime-after-mut.rs:2:13 + | +LL | fn x<'a>(x: &mut 'a i32){} + | ^^^^^^^ help: place the lifetime before `mut`: `&'a mut` + +error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a` + --> $DIR/issue-73568-lifetime-after-mut.rs:14:13 + | +LL | fn y<'a>(y: &mut 'a + Send) { + | ^^^^^^^^^^^^^^ help: try adding parentheses: `&mut ('a + Send)` + +error: lifetime must precede `mut` + --> $DIR/issue-73568-lifetime-after-mut.rs:6:22 + | +LL | fn w<$lt>(w: &mut $lt i32) {} + | ^^^^^^^^ help: place the lifetime before `mut`: `&$lt mut` +... +LL | mac!('a); + | --------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0423]: expected value, found trait `Send` + --> $DIR/issue-73568-lifetime-after-mut.rs:18:28 + | +LL | let z = y as &mut 'a + Send; + | ^^^^ not a value + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/issue-73568-lifetime-after-mut.rs:14:18 + | +LL | fn y<'a>(y: &mut 'a + Send) { + | ^^ help: use `dyn`: `dyn 'a` + | + = note: `#[warn(bare_trait_objects)]` on by default + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/issue-73568-lifetime-after-mut.rs:18:23 + | +LL | let z = y as &mut 'a + Send; + | ^^ help: use `dyn`: `dyn 'a` + +error[E0224]: at least one trait is required for an object type + --> $DIR/issue-73568-lifetime-after-mut.rs:14:18 + | +LL | fn y<'a>(y: &mut 'a + Send) { + | ^^ + +error: aborting due to 5 previous errors; 2 warnings emitted + +Some errors have detailed explanations: E0178, E0224, E0423. +For more information about an error, try `rustc --explain E0178`.