about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2020-01-15 18:34:30 -0800
committerEsteban Küber <esteban@kuber.com.ar>2020-01-19 17:31:33 -0800
commit6ba08755dfd9ddbb55248a0263a4e81d3602b410 (patch)
treece02b239a1a7b12bb4ced7592218a9d5cda62ba4 /src
parent7da653f669dcb97d40ca29b2937518bb8a12b775 (diff)
downloadrust-6ba08755dfd9ddbb55248a0263a4e81d3602b410.tar.gz
rust-6ba08755dfd9ddbb55248a0263a4e81d3602b410.zip
When encountering an undefined named lifetime, point to where it can be
This doesn't mention that using an existing lifetime is possible, but
that would hopefully be clear as always being an option. The intention
of this is to teach newcomers what the lifetime syntax is.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_resolve/lib.rs1
-rw-r--r--src/librustc_resolve/lifetimes.rs41
-rw-r--r--src/test/ui/error-codes/E0261.stderr6
-rw-r--r--src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr118
-rw-r--r--src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr18
-rw-r--r--src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr4
-rw-r--r--src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr2
-rw-r--r--src/test/ui/methods/method-call-lifetime-args-unresolved.stderr2
-rw-r--r--src/test/ui/parser/trait-object-trait-parens.stderr3
-rw-r--r--src/test/ui/regions/regions-in-enums.stderr4
-rw-r--r--src/test/ui/regions/regions-in-structs.stderr5
-rw-r--r--src/test/ui/regions/regions-name-undeclared.stderr46
-rw-r--r--src/test/ui/regions/regions-undeclared.stderr11
-rw-r--r--src/test/ui/where-clauses/where-lifetime-resolution.stderr6
14 files changed, 249 insertions, 18 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 60a0049f5da..29872be47c2 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -11,6 +11,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(label_break_value)]
 #![feature(nll)]
+#![feature(slice_patterns)]
 #![recursion_limit = "256"]
 
 pub use rustc_hir::def::{Namespace, PerNS};
diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs
index 5fae8f33187..f8e2f0cafff 100644
--- a/src/librustc_resolve/lifetimes.rs
+++ b/src/librustc_resolve/lifetimes.rs
@@ -183,6 +183,10 @@ struct LifetimeContext<'a, 'tcx> {
     xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
 
     lifetime_uses: &'a mut DefIdMap<LifetimeUseSet<'tcx>>,
+
+    /// When encountering an undefined named lifetime, we will suggest introducing it in these
+    /// places.
+    missing_named_lifetime_spots: Vec<&'tcx hir::Generics<'tcx>>,
 }
 
 #[derive(Debug)]
@@ -342,6 +346,7 @@ fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap {
             labels_in_fn: vec![],
             xcrate_object_lifetime_defaults: Default::default(),
             lifetime_uses: &mut Default::default(),
+            missing_named_lifetime_spots: vec![],
         };
         for (_, item) in &krate.items {
             visitor.visit_item(item);
@@ -384,9 +389,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         match item.kind {
             hir::ItemKind::Fn(ref sig, ref generics, _) => {
+                self.missing_named_lifetime_spots.push(generics);
                 self.visit_early_late(None, &sig.decl, generics, |this| {
                     intravisit::walk_item(this, item);
                 });
+                self.missing_named_lifetime_spots.pop();
             }
 
             hir::ItemKind::ExternCrate(_)
@@ -417,6 +424,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             | hir::ItemKind::Trait(_, _, ref generics, ..)
             | hir::ItemKind::TraitAlias(ref generics, ..)
             | hir::ItemKind::Impl { ref generics, .. } => {
+                self.missing_named_lifetime_spots.push(generics);
+
                 // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
                 // This is not true for other kinds of items.x
                 let track_lifetime_uses = match item.kind {
@@ -454,6 +463,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     this.check_lifetime_params(old_scope, &generics.params);
                     intravisit::walk_item(this, item);
                 });
+                self.missing_named_lifetime_spots.pop();
             }
         }
     }
@@ -686,6 +696,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         use self::hir::TraitItemKind::*;
+        self.missing_named_lifetime_spots.push(&trait_item.generics);
         match trait_item.kind {
             Method(ref sig, _) => {
                 let tcx = self.tcx;
@@ -737,10 +748,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 intravisit::walk_trait_item(self, trait_item);
             }
         }
+        self.missing_named_lifetime_spots.pop();
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         use self::hir::ImplItemKind::*;
+        self.missing_named_lifetime_spots.push(&impl_item.generics);
         match impl_item.kind {
             Method(ref sig, _) => {
                 let tcx = self.tcx;
@@ -824,6 +837,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 intravisit::walk_impl_item(self, impl_item);
             }
         }
+        self.missing_named_lifetime_spots.pop();
     }
 
     fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
@@ -1306,7 +1320,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     where
         F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>),
     {
-        let LifetimeContext { tcx, map, lifetime_uses, .. } = self;
+        let LifetimeContext { tcx, map, lifetime_uses, missing_named_lifetime_spots, .. } = self;
         let labels_in_fn = take(&mut self.labels_in_fn);
         let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
         let mut this = LifetimeContext {
@@ -1317,7 +1331,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             is_in_fn_syntax: self.is_in_fn_syntax,
             labels_in_fn,
             xcrate_object_lifetime_defaults,
-            lifetime_uses: lifetime_uses,
+            lifetime_uses,
+            missing_named_lifetime_spots: missing_named_lifetime_spots.to_vec(),
         };
         debug!("entering scope {:?}", this.scope);
         f(self.scope, &mut this);
@@ -1807,15 +1822,29 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
             self.insert_lifetime(lifetime_ref, def);
         } else {
-            struct_span_err!(
+            let mut err = struct_span_err!(
                 self.tcx.sess,
                 lifetime_ref.span,
                 E0261,
                 "use of undeclared lifetime name `{}`",
                 lifetime_ref
-            )
-            .span_label(lifetime_ref.span, "undeclared lifetime")
-            .emit();
+            );
+            err.span_label(lifetime_ref.span, "undeclared lifetime");
+            if !self.is_in_fn_syntax {
+                for generics in &self.missing_named_lifetime_spots {
+                    let (span, sugg) = match &generics.params {
+                        [] => (generics.span, format!("<{}>", lifetime_ref)),
+                        [param, ..] => (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)),
+                    };
+                    err.span_suggestion(
+                        span,
+                        &format!("consider introducing lifetime `{}` here", lifetime_ref),
+                        sugg,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+            err.emit();
         }
     }
 
diff --git a/src/test/ui/error-codes/E0261.stderr b/src/test/ui/error-codes/E0261.stderr
index 3bf5e9d8154..0eab2dc0ee0 100644
--- a/src/test/ui/error-codes/E0261.stderr
+++ b/src/test/ui/error-codes/E0261.stderr
@@ -2,11 +2,15 @@ error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/E0261.rs:1:12
    |
 LL | fn foo(x: &'a str) { }
-   |            ^^ undeclared lifetime
+   |       -    ^^ undeclared lifetime
+   |       |
+   |       help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/E0261.rs:5:9
    |
+LL | struct Foo {
+   |           - help: consider introducing lifetime `'a` here: `<'a>`
 LL |     x: &'a str,
    |         ^^ undeclared lifetime
 
diff --git a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr b/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr
index 5c64bf6539c..bbf3ea8a89f 100644
--- a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr
+++ b/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr
@@ -2,103 +2,207 @@ error[E0261]: use of undeclared lifetime name `'x`
   --> $DIR/feature-gate-in_band_lifetimes.rs:3:12
    |
 LL | fn foo(x: &'x u8) -> &'x u8 { x }
-   |            ^^ undeclared lifetime
+   |       -    ^^ undeclared lifetime
+   |       |
+   |       help: consider introducing lifetime `'x` here: `<'x>`
 
 error[E0261]: use of undeclared lifetime name `'x`
   --> $DIR/feature-gate-in_band_lifetimes.rs:3:23
    |
 LL | fn foo(x: &'x u8) -> &'x u8 { x }
-   |                       ^^ undeclared lifetime
+   |       -               ^^ undeclared lifetime
+   |       |
+   |       help: consider introducing lifetime `'x` here: `<'x>`
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:15:12
    |
 LL | impl<'a> X<'b> {
-   |            ^^ undeclared lifetime
+   |      -     ^^ undeclared lifetime
+   |      |
+   |      help: consider introducing lifetime `'b` here: `'b,`
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:17:27
    |
 LL |     fn inner_2(&self) -> &'b u8 {
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> X<'b> {
+   |      ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn inner_2<'b>(&self) -> &'b u8 {
+   |               ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:23:8
    |
 LL | impl X<'b> {
-   |        ^^ undeclared lifetime
+   |     -  ^^ undeclared lifetime
+   |     |
+   |     help: consider introducing lifetime `'b` here: `<'b>`
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:25:27
    |
 LL |     fn inner_3(&self) -> &'b u8 {
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b> X<'b> {
+   |     ^^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn inner_3<'b>(&self) -> &'b u8 {
+   |               ^^^^
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/feature-gate-in_band_lifetimes.rs:33:9
    |
 LL | impl Y<&'a u8> {
-   |         ^^ undeclared lifetime
+   |     -   ^^ undeclared lifetime
+   |     |
+   |     help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/feature-gate-in_band_lifetimes.rs:35:25
    |
 LL |     fn inner(&self) -> &'a u8 {
    |                         ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'a` here
+   |
+LL | impl<'a> Y<&'a u8> {
+   |     ^^^^
+help: consider introducing lifetime `'a` here
+   |
+LL |     fn inner<'a>(&self) -> &'a u8 {
+   |             ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:43:27
    |
 LL |     fn any_lifetime() -> &'b u8;
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait MyTrait<'b, 'a> {
+   |               ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn any_lifetime<'b>() -> &'b u8;
+   |                    ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:45:27
    |
 LL |     fn borrowed_lifetime(&'b self) -> &'b u8;
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait MyTrait<'b, 'a> {
+   |               ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn borrowed_lifetime<'b>(&'b self) -> &'b u8;
+   |                         ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:45:40
    |
 LL |     fn borrowed_lifetime(&'b self) -> &'b u8;
    |                                        ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait MyTrait<'b, 'a> {
+   |               ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn borrowed_lifetime<'b>(&'b self) -> &'b u8;
+   |                         ^^^^
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/feature-gate-in_band_lifetimes.rs:50:14
    |
 LL | impl MyTrait<'a> for Y<&'a u8> {
-   |              ^^ undeclared lifetime
+   |     -        ^^ undeclared lifetime
+   |     |
+   |     help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/feature-gate-in_band_lifetimes.rs:50:25
    |
 LL | impl MyTrait<'a> for Y<&'a u8> {
-   |                         ^^ undeclared lifetime
+   |     -                   ^^ undeclared lifetime
+   |     |
+   |     help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/feature-gate-in_band_lifetimes.rs:53:31
    |
 LL |     fn my_lifetime(&self) -> &'a u8 { self.0 }
    |                               ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'a` here
+   |
+LL | impl<'a> MyTrait<'a> for Y<&'a u8> {
+   |     ^^^^
+help: consider introducing lifetime `'a` here
+   |
+LL |     fn my_lifetime<'a>(&self) -> &'a u8 { self.0 }
+   |                   ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:55:27
    |
 LL |     fn any_lifetime() -> &'b u8 { &0 }
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
+   |     ^^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn any_lifetime<'b>() -> &'b u8 { &0 }
+   |                    ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:57:27
    |
 LL |     fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
+   |     ^^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 }
+   |                         ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:57:40
    |
 LL |     fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
    |                                        ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
+   |     ^^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 }
+   |                         ^^^^
 
 error: aborting due to 17 previous errors
 
diff --git a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr
index 81137e81dc4..fc2ce1cb866 100644
--- a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr
+++ b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr
@@ -3,12 +3,30 @@ error[E0261]: use of undeclared lifetime name `'b`
    |
 LL |         + Deref<Target = Self::Item<'b>>;
    |                                     ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait Iterable<'b> {
+   |               ^^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     type Iter<'b, 'a>: Iterator<Item = Self::Item<'a>>
+   |               ^^^
 
 error[E0261]: use of undeclared lifetime name `'undeclared`
   --> $DIR/generic_associated_type_undeclared_lifetimes.rs:12:41
    |
 LL |     fn iter<'a>(&'a self) -> Self::Iter<'undeclared>;
    |                                         ^^^^^^^^^^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'undeclared` here
+   |
+LL | trait Iterable<'undeclared> {
+   |               ^^^^^^^^^^^^^
+help: consider introducing lifetime `'undeclared` here
+   |
+LL |     fn iter<'undeclared, 'a>(&'a self) -> Self::Iter<'undeclared>;
+   |             ^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr b/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr
index a270dd03926..fe656f7af7e 100644
--- a/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr
+++ b/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr
@@ -1,12 +1,16 @@
 error[E0261]: use of undeclared lifetime name `'test`
   --> $DIR/no_in_band_in_struct.rs:5:9
    |
+LL | struct Foo {
+   |           - help: consider introducing lifetime `'test` here: `<'test>`
 LL |     x: &'test u32,
    |         ^^^^^ undeclared lifetime
 
 error[E0261]: use of undeclared lifetime name `'test`
   --> $DIR/no_in_band_in_struct.rs:9:10
    |
+LL | enum Bar {
+   |         - help: consider introducing lifetime `'test` here: `<'test>`
 LL |     Baz(&'test u32),
    |          ^^^^^ undeclared lifetime
 
diff --git a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr
index c307066be6b..bfb20ade035 100644
--- a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr
+++ b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr
@@ -1,6 +1,8 @@
 error[E0261]: use of undeclared lifetime name `'test`
   --> $DIR/no_introducing_in_band_in_locals.rs:5:13
    |
+LL | fn foo(x: &u32) {
+   |       - help: consider introducing lifetime `'test` here: `<'test>`
 LL |     let y: &'test u32 = x;
    |             ^^^^^ undeclared lifetime
 
diff --git a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr
index 67fd8d7a13e..c9f235c4f7d 100644
--- a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr
+++ b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr
@@ -1,6 +1,8 @@
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/method-call-lifetime-args-unresolved.rs:2:15
    |
+LL | fn main() {
+   |        - help: consider introducing lifetime `'a` here: `<'a>`
 LL |     0.clone::<'a>();
    |               ^^ undeclared lifetime
 
diff --git a/src/test/ui/parser/trait-object-trait-parens.stderr b/src/test/ui/parser/trait-object-trait-parens.stderr
index 03fb764ee03..4b9f49423cb 100644
--- a/src/test/ui/parser/trait-object-trait-parens.stderr
+++ b/src/test/ui/parser/trait-object-trait-parens.stderr
@@ -33,6 +33,9 @@ LL |     let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>;
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/trait-object-trait-parens.rs:11:31
    |
+LL | fn main() {
+   |        - help: consider introducing lifetime `'a` here: `<'a>`
+...
 LL |     let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>;
    |                               ^^ undeclared lifetime
 
diff --git a/src/test/ui/regions/regions-in-enums.stderr b/src/test/ui/regions/regions-in-enums.stderr
index cfed9feba4b..66537653291 100644
--- a/src/test/ui/regions/regions-in-enums.stderr
+++ b/src/test/ui/regions/regions-in-enums.stderr
@@ -1,12 +1,16 @@
 error[E0261]: use of undeclared lifetime name `'foo`
   --> $DIR/regions-in-enums.rs:13:9
    |
+LL | enum No0 {
+   |         - help: consider introducing lifetime `'foo` here: `<'foo>`
 LL |     X5(&'foo usize)
    |         ^^^^ undeclared lifetime
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-in-enums.rs:17:9
    |
+LL | enum No1 {
+   |         - help: consider introducing lifetime `'a` here: `<'a>`
 LL |     X6(&'a usize)
    |         ^^ undeclared lifetime
 
diff --git a/src/test/ui/regions/regions-in-structs.stderr b/src/test/ui/regions/regions-in-structs.stderr
index 8314942759d..5dfdc2ee93b 100644
--- a/src/test/ui/regions/regions-in-structs.stderr
+++ b/src/test/ui/regions/regions-in-structs.stderr
@@ -1,12 +1,17 @@
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-in-structs.rs:10:9
    |
+LL | struct StructDecl {
+   |                  - help: consider introducing lifetime `'a` here: `<'a>`
 LL |     a: &'a isize,
    |         ^^ undeclared lifetime
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-in-structs.rs:11:9
    |
+LL | struct StructDecl {
+   |                  - help: consider introducing lifetime `'a` here: `<'a>`
+LL |     a: &'a isize,
 LL |     b: &'a isize,
    |         ^^ undeclared lifetime
 
diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr
index 5f6a48a35f3..79ebef41dcc 100644
--- a/src/test/ui/regions/regions-name-undeclared.stderr
+++ b/src/test/ui/regions/regions-name-undeclared.stderr
@@ -3,34 +3,67 @@ error[E0261]: use of undeclared lifetime name `'b`
    |
 LL |     fn m4(&self, arg: &'b isize) { }
    |                        ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> Foo<'a> {
+   |      ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn m4<'b>(&self, arg: &'b isize) { }
+   |          ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:16:12
    |
 LL |     fn m5(&'b self) { }
    |            ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> Foo<'a> {
+   |      ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn m5<'b>(&'b self) { }
+   |          ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:17:27
    |
 LL |     fn m6(&self, arg: Foo<'b>) { }
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> Foo<'a> {
+   |      ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn m6<'b>(&self, arg: Foo<'b>) { }
+   |          ^^^^
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-name-undeclared.rs:25:22
    |
 LL |     type X = Option<&'a isize>;
-   |                      ^^ undeclared lifetime
+   |           -          ^^ undeclared lifetime
+   |           |
+   |           help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-name-undeclared.rs:27:13
    |
+LL |     enum E {
+   |           - help: consider introducing lifetime `'a` here: `<'a>`
 LL |         E1(&'a isize)
    |             ^^ undeclared lifetime
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-name-undeclared.rs:30:13
    |
+LL |     struct S {
+   |             - help: consider introducing lifetime `'a` here: `<'a>`
 LL |         f: &'a isize
    |             ^^ undeclared lifetime
 
@@ -38,13 +71,17 @@ error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-name-undeclared.rs:32:14
    |
 LL |     fn f(a: &'a isize) { }
-   |              ^^ undeclared lifetime
+   |         -    ^^ undeclared lifetime
+   |         |
+   |         help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-name-undeclared.rs:40:17
    |
 LL | fn fn_types(a: &'a isize,
-   |                 ^^ undeclared lifetime
+   |            -    ^^ undeclared lifetime
+   |            |
+   |            help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:42:36
@@ -61,6 +98,9 @@ LL | ...                   &'b isize)>,
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-name-undeclared.rs:46:17
    |
+LL | fn fn_types(a: &'a isize,
+   |            - help: consider introducing lifetime `'a` here: `<'a>`
+...
 LL |             c: &'a isize)
    |                 ^^ undeclared lifetime
 
diff --git a/src/test/ui/regions/regions-undeclared.stderr b/src/test/ui/regions/regions-undeclared.stderr
index 495aec3fde5..6bfde5524ac 100644
--- a/src/test/ui/regions/regions-undeclared.stderr
+++ b/src/test/ui/regions/regions-undeclared.stderr
@@ -7,12 +7,17 @@ LL | static c_x: &'blk isize = &22;
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-undeclared.rs:4:10
    |
+LL | enum EnumDecl {
+   |              - help: consider introducing lifetime `'a` here: `<'a>`
 LL |     Foo(&'a isize),
    |          ^^ undeclared lifetime
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-undeclared.rs:5:10
    |
+LL | enum EnumDecl {
+   |              - help: consider introducing lifetime `'a` here: `<'a>`
+LL |     Foo(&'a isize),
 LL |     Bar(&'a isize),
    |          ^^ undeclared lifetime
 
@@ -20,11 +25,15 @@ error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-undeclared.rs:8:15
    |
 LL | fn fnDecl(x: &'a isize,
-   |               ^^ undeclared lifetime
+   |          -    ^^ undeclared lifetime
+   |          |
+   |          help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-undeclared.rs:9:15
    |
+LL | fn fnDecl(x: &'a isize,
+   |          - help: consider introducing lifetime `'a` here: `<'a>`
 LL |           y: &'a isize)
    |               ^^ undeclared lifetime
 
diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.stderr b/src/test/ui/where-clauses/where-lifetime-resolution.stderr
index 0081ae07163..49799a93017 100644
--- a/src/test/ui/where-clauses/where-lifetime-resolution.stderr
+++ b/src/test/ui/where-clauses/where-lifetime-resolution.stderr
@@ -1,6 +1,9 @@
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/where-lifetime-resolution.rs:6:38
    |
+LL | fn f() where
+   |     - help: consider introducing lifetime `'a` here: `<'a>`
+LL |     for<'a> dyn Trait1<'a>: Trait1<'a>, // OK
 LL |     (dyn for<'a> Trait1<'a>): Trait1<'a>,
    |                                      ^^ undeclared lifetime
 
@@ -13,6 +16,9 @@ LL |     for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/where-lifetime-resolution.rs:8:52
    |
+LL | fn f() where
+   |     - help: consider introducing lifetime `'b` here: `<'b>`
+...
 LL |     for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
    |                                                    ^^ undeclared lifetime