about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_resolve/src/late.rs78
-rw-r--r--tests/crashes/122903-1.rs4
-rw-r--r--tests/crashes/122903-2.rs9
-rw-r--r--tests/ui/self/elision/ignore-non-reference-lifetimes.rs22
-rw-r--r--tests/ui/self/elision/multiple-ref-self-async.rs6
-rw-r--r--tests/ui/self/elision/multiple-ref-self-async.stderr63
-rw-r--r--tests/ui/self/elision/multiple-ref-self.rs7
-rw-r--r--tests/ui/self/elision/multiple-ref-self.stderr63
-rw-r--r--tests/ui/self/elision/no-shadow-pin-self.rs17
-rw-r--r--tests/ui/self/elision/no-shadow-pin-self.stderr32
-rw-r--r--tests/ui/self/elision/ref-assoc-async.rs6
-rw-r--r--tests/ui/self/elision/ref-assoc-async.stderr77
-rw-r--r--tests/ui/self/elision/ref-assoc.rs7
-rw-r--r--tests/ui/self/elision/ref-assoc.stderr77
-rw-r--r--tests/ui/self/elision/ref-self-multi.rs29
-rw-r--r--tests/ui/self/elision/ref-self-multi.stderr27
-rw-r--r--tests/ui/self/elision/ref-self.fixed7
-rw-r--r--tests/ui/self/elision/ref-self.rs7
-rw-r--r--tests/ui/self/elision/ref-self.stderr31
19 files changed, 522 insertions, 47 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 1d37264f96a..dc7200465d9 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2175,13 +2175,17 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             // Handle `self` specially.
             if index == 0 && has_self {
                 let self_lifetime = self.find_lifetime_for_self(ty);
-                if let Set1::One(lifetime) = self_lifetime {
+                elision_lifetime = match self_lifetime {
                     // We found `self` elision.
-                    elision_lifetime = Elision::Self_(lifetime);
-                } else {
+                    Set1::One(lifetime) => Elision::Self_(lifetime),
+                    // `self` itself had ambiguous lifetimes, e.g.
+                    // &Box<&Self>. In this case we won't consider
+                    // taking an alternative parameter lifetime; just avoid elision
+                    // entirely.
+                    Set1::Many => Elision::Err,
                     // We do not have `self` elision: disregard the `Elision::Param` that we may
                     // have found.
-                    elision_lifetime = Elision::None;
+                    Set1::Empty => Elision::None,
                 }
             }
             debug!("(resolving function / closure) recorded parameter");
@@ -2201,15 +2205,55 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
 
     /// List all the lifetimes that appear in the provided type.
     fn find_lifetime_for_self(&self, ty: &'ast Ty) -> Set1<LifetimeRes> {
-        struct SelfVisitor<'r, 'a, 'tcx> {
+        /// Visits a type to find all the &references, and determines the
+        /// set of lifetimes for all of those references where the referent
+        /// contains Self.
+        struct FindReferenceVisitor<'r, 'a, 'tcx> {
             r: &'r Resolver<'a, 'tcx>,
             impl_self: Option<Res>,
             lifetime: Set1<LifetimeRes>,
         }
 
+        impl<'a> Visitor<'a> for FindReferenceVisitor<'_, '_, '_> {
+            fn visit_ty(&mut self, ty: &'a Ty) {
+                trace!("FindReferenceVisitor considering ty={:?}", ty);
+                if let TyKind::Ref(lt, _) = ty.kind {
+                    // See if anything inside the &thing contains Self
+                    let mut visitor =
+                        SelfVisitor { r: self.r, impl_self: self.impl_self, self_found: false };
+                    visitor.visit_ty(ty);
+                    trace!("FindReferenceVisitor: SelfVisitor self_found={:?}", visitor.self_found);
+                    if visitor.self_found {
+                        let lt_id = if let Some(lt) = lt {
+                            lt.id
+                        } else {
+                            let res = self.r.lifetimes_res_map[&ty.id];
+                            let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() };
+                            start
+                        };
+                        let lt_res = self.r.lifetimes_res_map[&lt_id];
+                        trace!("FindReferenceVisitor inserting res={:?}", lt_res);
+                        self.lifetime.insert(lt_res);
+                    }
+                }
+                visit::walk_ty(self, ty)
+            }
+
+            // A type may have an expression as a const generic argument.
+            // We do not want to recurse into those.
+            fn visit_expr(&mut self, _: &'a Expr) {}
+        }
+
+        /// Visitor which checks the referent of a &Thing to see if the
+        /// Thing contains Self
+        struct SelfVisitor<'r, 'a, 'tcx> {
+            r: &'r Resolver<'a, 'tcx>,
+            impl_self: Option<Res>,
+            self_found: bool,
+        }
+
         impl SelfVisitor<'_, '_, '_> {
-            // Look for `self: &'a Self` - also desugared from `&'a self`,
-            // and if that matches, use it for elision and return early.
+            // Look for `self: &'a Self` - also desugared from `&'a self`
             fn is_self_ty(&self, ty: &Ty) -> bool {
                 match ty.kind {
                     TyKind::ImplicitSelf => true,
@@ -2228,19 +2272,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> {
             fn visit_ty(&mut self, ty: &'a Ty) {
                 trace!("SelfVisitor considering ty={:?}", ty);
-                if let TyKind::Ref(lt, ref mt) = ty.kind
-                    && self.is_self_ty(&mt.ty)
-                {
-                    let lt_id = if let Some(lt) = lt {
-                        lt.id
-                    } else {
-                        let res = self.r.lifetimes_res_map[&ty.id];
-                        let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() };
-                        start
-                    };
-                    let lt_res = self.r.lifetimes_res_map[&lt_id];
-                    trace!("SelfVisitor inserting res={:?}", lt_res);
-                    self.lifetime.insert(lt_res);
+                if self.is_self_ty(ty) {
+                    trace!("SelfVisitor found Self");
+                    self.self_found = true;
                 }
                 visit::walk_ty(self, ty)
             }
@@ -2271,9 +2305,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                     Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_)
                 )
             });
-        let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
+        let mut visitor = FindReferenceVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
         visitor.visit_ty(ty);
-        trace!("SelfVisitor found={:?}", visitor.lifetime);
+        trace!("FindReferenceVisitor found={:?}", visitor.lifetime);
         visitor.lifetime
     }
 
diff --git a/tests/crashes/122903-1.rs b/tests/crashes/122903-1.rs
index 9323c435851..0953962ed9e 100644
--- a/tests/crashes/122903-1.rs
+++ b/tests/crashes/122903-1.rs
@@ -1,7 +1,7 @@
 //@ known-bug: #122903
 impl Struct {
-    async fn box_box_ref_Struct(
-        self: Box<Box<Self, impl FnMut(&mut Box<Box<Self, impl FnMut(&mut Self)>>)>>,
+    fn box_box_ref_Struct(
+        self: impl FnMut(Box<impl FnMut(&mut Self)>),
     ) -> &u32 {
         f
     }
diff --git a/tests/crashes/122903-2.rs b/tests/crashes/122903-2.rs
deleted file mode 100644
index 0d5d93014c1..00000000000
--- a/tests/crashes/122903-2.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ known-bug: #122903
-
-impl Struct {
-    async fn box_box_ref_Struct(
-        self: Box<Box<Self, impl FnMut(&mut Box<Box<Self, impl FnMut(&mut Self)>>)>>
-    ) -> &u32 {
-        f
-    }
-}
diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
new file mode 100644
index 00000000000..f7f61b8c810
--- /dev/null
+++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
@@ -0,0 +1,22 @@
+//@ check-pass
+
+struct Foo<'a>(&'a str);
+
+impl<'b> Foo<'b> {
+    fn a<'a>(self: Self, a: &'a str) -> &str {
+        a
+    }
+    fn b<'a>(self: Foo<'b>, a: &'a str) -> &str {
+        a
+    }
+}
+
+struct Foo2<'a>(&'a u32);
+impl<'a> Foo2<'a> {
+    fn foo(self: &Self) -> &u32 { self.0 } // ok
+    fn bar(self: &Foo2<'a>) -> &u32 { self.0 } // ok (do not look into `Foo`)
+    fn baz2(self: Self, arg: &u32) -> &u32 { arg } // use lt from `arg`
+    fn baz3(self: Foo2<'a>, arg: &u32) -> &u32 { arg } // use lt from `arg`
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/multiple-ref-self-async.rs b/tests/ui/self/elision/multiple-ref-self-async.rs
index fb77f91396c..f63b455901e 100644
--- a/tests/ui/self/elision/multiple-ref-self-async.rs
+++ b/tests/ui/self/elision/multiple-ref-self-async.rs
@@ -1,4 +1,3 @@
-//@ check-pass
 //@ edition:2018
 
 #![feature(arbitrary_self_types)]
@@ -21,22 +20,27 @@ impl Struct {
     // Test using multiple `&Self`:
 
     async fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
+        //~^ ERROR missing lifetime specifier
         f
     }
 
     async fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
+        //~^ ERROR missing lifetime specifier
         f
     }
 
     async fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
+        //~^ ERROR missing lifetime specifier
         f
     }
 
     async fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
+        //~^ ERROR missing lifetime specifier
         f
     }
 
     async fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
+        //~^ ERROR missing lifetime specifier
         f
     }
 }
diff --git a/tests/ui/self/elision/multiple-ref-self-async.stderr b/tests/ui/self/elision/multiple-ref-self-async.stderr
new file mode 100644
index 00000000000..e2abc7c1e78
--- /dev/null
+++ b/tests/ui/self/elision/multiple-ref-self-async.stderr
@@ -0,0 +1,63 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/multiple-ref-self-async.rs:22:74
+   |
+LL |     async fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
+   |                                           ------------------     ---     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
+help: consider introducing a named lifetime parameter
+   |
+LL |     async fn wrap_ref_Self_ref_Self<'a>(self: Wrap<&'a Self, &'a Self>, f: &'a u8) -> &'a u8 {
+   |                                    ++++             ++        ++            ++         ++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/multiple-ref-self-async.rs:27:84
+   |
+LL |     async fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
+   |                                               -----------------------     ----     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
+help: consider introducing a named lifetime parameter
+   |
+LL |     async fn box_wrap_ref_Self_ref_Self<'a>(self: Box<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 {
+   |                                        ++++                 ++        ++             ++          ++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/multiple-ref-self-async.rs:32:84
+   |
+LL |     async fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
+   |                                               -----------------------     ----     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
+help: consider introducing a named lifetime parameter
+   |
+LL |     async fn pin_wrap_ref_Self_ref_Self<'a>(self: Pin<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 {
+   |                                        ++++                 ++        ++             ++          ++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/multiple-ref-self-async.rs:37:93
+   |
+LL |     async fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
+   |                                                   ----------------------------     ----     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
+help: consider introducing a named lifetime parameter
+   |
+LL |     async fn box_box_wrap_ref_Self_ref_Self<'a>(self: Box<Box<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 {
+   |                                            ++++                     ++        ++              ++          ++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/multiple-ref-self-async.rs:42:93
+   |
+LL |     async fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
+   |                                                   ----------------------------     ----     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
+help: consider introducing a named lifetime parameter
+   |
+LL |     async fn box_pin_wrap_ref_Self_ref_Self<'a>(self: Box<Pin<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 {
+   |                                            ++++                     ++        ++              ++          ++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
diff --git a/tests/ui/self/elision/multiple-ref-self.rs b/tests/ui/self/elision/multiple-ref-self.rs
index 01d6bb47c04..dd9b138051d 100644
--- a/tests/ui/self/elision/multiple-ref-self.rs
+++ b/tests/ui/self/elision/multiple-ref-self.rs
@@ -1,5 +1,3 @@
-//@ check-pass
-
 #![feature(arbitrary_self_types)]
 #![allow(non_snake_case)]
 
@@ -20,22 +18,27 @@ impl Struct {
     // Test using multiple `&Self`:
 
     fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
+        //~^ ERROR missing lifetime specifier
         f
     }
 
     fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
+        //~^ ERROR missing lifetime specifier
         f
     }
 
     fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
+        //~^ ERROR missing lifetime specifier
         f
     }
 
     fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
+        //~^ ERROR missing lifetime specifier
         f
     }
 
     fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
+        //~^ ERROR missing lifetime specifier
         f
     }
 }
diff --git a/tests/ui/self/elision/multiple-ref-self.stderr b/tests/ui/self/elision/multiple-ref-self.stderr
new file mode 100644
index 00000000000..24d74d352e4
--- /dev/null
+++ b/tests/ui/self/elision/multiple-ref-self.stderr
@@ -0,0 +1,63 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/multiple-ref-self.rs:20:68
+   |
+LL |     fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
+   |                                     ------------------     ---     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn wrap_ref_Self_ref_Self<'a>(self: Wrap<&'a Self, &'a Self>, f: &'a u8) -> &'a u8 {
+   |                              ++++             ++        ++            ++         ++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/multiple-ref-self.rs:25:78
+   |
+LL |     fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
+   |                                         -----------------------     ----     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn box_wrap_ref_Self_ref_Self<'a>(self: Box<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 {
+   |                                  ++++                 ++        ++             ++          ++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/multiple-ref-self.rs:30:78
+   |
+LL |     fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
+   |                                         -----------------------     ----     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn pin_wrap_ref_Self_ref_Self<'a>(self: Pin<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 {
+   |                                  ++++                 ++        ++             ++          ++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/multiple-ref-self.rs:35:87
+   |
+LL |     fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
+   |                                             ----------------------------     ----     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn box_box_wrap_ref_Self_ref_Self<'a>(self: Box<Box<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 {
+   |                                      ++++                     ++        ++              ++          ++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/multiple-ref-self.rs:40:87
+   |
+LL |     fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
+   |                                             ----------------------------     ----     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn box_pin_wrap_ref_Self_ref_Self<'a>(self: Box<Pin<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 {
+   |                                      ++++                     ++        ++              ++          ++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
diff --git a/tests/ui/self/elision/no-shadow-pin-self.rs b/tests/ui/self/elision/no-shadow-pin-self.rs
new file mode 100644
index 00000000000..e390b869ca7
--- /dev/null
+++ b/tests/ui/self/elision/no-shadow-pin-self.rs
@@ -0,0 +1,17 @@
+use std::pin::Pin;
+trait Trait {
+    fn method<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 {
+        f
+    }
+}
+
+impl<P> Trait for Pin<P> {
+    // This should not hide `&Self`, which would cause this to compile.
+    fn method(self: Pin<&Self>, f: &u32) -> &u32 {
+        //~^ ERROR `impl` item signature doesn't match `trait`
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/no-shadow-pin-self.stderr b/tests/ui/self/elision/no-shadow-pin-self.stderr
new file mode 100644
index 00000000000..23485e9de79
--- /dev/null
+++ b/tests/ui/self/elision/no-shadow-pin-self.stderr
@@ -0,0 +1,32 @@
+error: `impl` item signature doesn't match `trait` item signature
+  --> $DIR/no-shadow-pin-self.rs:10:5
+   |
+LL |     fn method<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 {
+   |     ------------------------------------------------------ expected `fn(Pin<&'1 Pin<P>>, &'a u32) -> &'a u32`
+...
+LL |     fn method(self: Pin<&Self>, f: &u32) -> &u32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(Pin<&'1 Pin<P>>, &'2 u32) -> &'1 u32`
+   |
+   = note: expected signature `fn(Pin<&'1 Pin<P>>, &'a u32) -> &'a u32`
+              found signature `fn(Pin<&'1 Pin<P>>, &'2 u32) -> &'1 u32`
+   = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+   = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
+
+error: lifetime may not live long enough
+  --> $DIR/no-shadow-pin-self.rs:12:9
+   |
+LL |     fn method(self: Pin<&Self>, f: &u32) -> &u32 {
+   |                         -          - let's call the lifetime of this reference `'1`
+   |                         |
+   |                         let's call the lifetime of this reference `'2`
+LL |
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn method<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 {
+   |              ++++                       ++          ++
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/self/elision/ref-assoc-async.rs b/tests/ui/self/elision/ref-assoc-async.rs
index 2af4f13a41b..25deb25253d 100644
--- a/tests/ui/self/elision/ref-assoc-async.rs
+++ b/tests/ui/self/elision/ref-assoc-async.rs
@@ -1,5 +1,4 @@
 //@ edition:2018
-//@ check-pass
 
 #![allow(non_snake_case)]
 
@@ -18,22 +17,27 @@ impl Trait for Struct {
 impl Struct {
     async fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
         f
+        //~^ ERROR lifetime may not live long enough
     }
 
     async fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
         f
+        //~^ ERROR lifetime may not live long enough
     }
 
     async fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
         f
+        //~^ ERROR lifetime may not live long enough
     }
 
     async fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
         f
+        //~^ ERROR lifetime may not live long enough
     }
 
     async fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
         f
+        //~^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/tests/ui/self/elision/ref-assoc-async.stderr b/tests/ui/self/elision/ref-assoc-async.stderr
new file mode 100644
index 00000000000..cf54a86b45f
--- /dev/null
+++ b/tests/ui/self/elision/ref-assoc-async.stderr
@@ -0,0 +1,77 @@
+error: lifetime may not live long enough
+  --> $DIR/ref-assoc-async.rs:19:9
+   |
+LL |     async fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
+   |                                  -                                 - let's call the lifetime of this reference `'1`
+   |                                  |
+   |                                  let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_AssocType<'a>(self: &'a <Struct as Trait>::AssocType, f: &'a u32) -> &u32 {
+   |                           ++++        ++                                   ++
+
+error: lifetime may not live long enough
+  --> $DIR/ref-assoc-async.rs:24:9
+   |
+LL |     async fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
+   |                                          -                                  - let's call the lifetime of this reference `'1`
+   |                                          |
+   |                                          let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_AssocType<'a>(self: Box<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &u32 {
+   |                               ++++            ++                                    ++
+
+error: lifetime may not live long enough
+  --> $DIR/ref-assoc-async.rs:29:9
+   |
+LL |     async fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
+   |                                          -                                  - let's call the lifetime of this reference `'1`
+   |                                          |
+   |                                          let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_AssocType<'a>(self: Pin<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &u32 {
+   |                               ++++            ++                                    ++
+
+error: lifetime may not live long enough
+  --> $DIR/ref-assoc-async.rs:34:9
+   |
+LL |     async fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
+   |                                                  -                                   - let's call the lifetime of this reference `'1`
+   |                                                  |
+   |                                                  let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_AssocType<'a>(self: Box<Box<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &u32 {
+   |                                   ++++                ++                                     ++
+
+error: lifetime may not live long enough
+  --> $DIR/ref-assoc-async.rs:39:9
+   |
+LL |     async fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
+   |                                                  -                                   - let's call the lifetime of this reference `'1`
+   |                                                  |
+   |                                                  let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_ref_AssocType<'a>(self: Box<Pin<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &u32 {
+   |                                   ++++                ++                                     ++
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/self/elision/ref-assoc.rs b/tests/ui/self/elision/ref-assoc.rs
index 8dc78d31d39..01d2556df62 100644
--- a/tests/ui/self/elision/ref-assoc.rs
+++ b/tests/ui/self/elision/ref-assoc.rs
@@ -1,5 +1,3 @@
-//@ check-pass
-
 #![allow(non_snake_case)]
 
 use std::pin::Pin;
@@ -17,22 +15,27 @@ impl Trait for Struct {
 impl Struct {
     fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
         f
+        //~^ ERROR lifetime may not live long enough
     }
 
     fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
         f
+        //~^ ERROR lifetime may not live long enough
     }
 
     fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
         f
+        //~^ ERROR lifetime may not live long enough
     }
 
     fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
         f
+        //~^ ERROR lifetime may not live long enough
     }
 
     fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
         f
+        //~^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/tests/ui/self/elision/ref-assoc.stderr b/tests/ui/self/elision/ref-assoc.stderr
new file mode 100644
index 00000000000..7c8a1de95ae
--- /dev/null
+++ b/tests/ui/self/elision/ref-assoc.stderr
@@ -0,0 +1,77 @@
+error: lifetime may not live long enough
+  --> $DIR/ref-assoc.rs:17:9
+   |
+LL |     fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
+   |                            -                                 - let's call the lifetime of this reference `'1`
+   |                            |
+   |                            let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn ref_AssocType<'a>(self: &<Struct as Trait>::AssocType, f: &'a u32) -> &'a u32 {
+   |                     ++++                                          ++          ++
+
+error: lifetime may not live long enough
+  --> $DIR/ref-assoc.rs:22:9
+   |
+LL |     fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
+   |                                    -                                  - let's call the lifetime of this reference `'1`
+   |                                    |
+   |                                    let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_ref_AssocType<'a>(self: Box<&<Struct as Trait>::AssocType>, f: &'a u32) -> &'a u32 {
+   |                         ++++                                               ++          ++
+
+error: lifetime may not live long enough
+  --> $DIR/ref-assoc.rs:27:9
+   |
+LL |     fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
+   |                                    -                                  - let's call the lifetime of this reference `'1`
+   |                                    |
+   |                                    let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn pin_ref_AssocType<'a>(self: Pin<&<Struct as Trait>::AssocType>, f: &'a u32) -> &'a u32 {
+   |                         ++++                                               ++          ++
+
+error: lifetime may not live long enough
+  --> $DIR/ref-assoc.rs:32:9
+   |
+LL |     fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
+   |                                            -                                   - let's call the lifetime of this reference `'1`
+   |                                            |
+   |                                            let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_box_ref_AssocType<'a>(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &'a u32) -> &'a u32 {
+   |                             ++++                                                    ++          ++
+
+error: lifetime may not live long enough
+  --> $DIR/ref-assoc.rs:37:9
+   |
+LL |     fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
+   |                                            -                                   - let's call the lifetime of this reference `'1`
+   |                                            |
+   |                                            let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_pin_ref_AssocType<'a>(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &'a u32) -> &'a u32 {
+   |                             ++++                                                    ++          ++
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/self/elision/ref-self-multi.rs b/tests/ui/self/elision/ref-self-multi.rs
new file mode 100644
index 00000000000..ed431a9c852
--- /dev/null
+++ b/tests/ui/self/elision/ref-self-multi.rs
@@ -0,0 +1,29 @@
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+#![allow(unused)]
+
+use std::marker::PhantomData;
+use std::ops::Deref;
+
+struct Struct { }
+
+struct Wrap<T, P>(T, PhantomData<P>);
+
+impl<T, P> Deref for Wrap<T, P> {
+    type Target = T;
+    fn deref(&self) -> &T { &self.0 }
+}
+
+impl Struct {
+    fn ref_box_ref_Self(self: &Box<&Self>, f: &u32) -> &u32 {
+        //~^ ERROR missing lifetime specifier
+        f
+    }
+
+    fn ref_wrap_ref_Self(self: &Wrap<&Self, u32>, f: &u32) -> &u32 {
+        //~^ ERROR missing lifetime specifier
+        f
+    }
+}
+
+fn main() { }
diff --git a/tests/ui/self/elision/ref-self-multi.stderr b/tests/ui/self/elision/ref-self-multi.stderr
new file mode 100644
index 00000000000..7e0451aa0d5
--- /dev/null
+++ b/tests/ui/self/elision/ref-self-multi.stderr
@@ -0,0 +1,27 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/ref-self-multi.rs:18:56
+   |
+LL |     fn ref_box_ref_Self(self: &Box<&Self>, f: &u32) -> &u32 {
+   |                               -----------     ----     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn ref_box_ref_Self<'a>(self: &'a Box<&'a Self>, f: &'a u32) -> &'a u32 {
+   |                        ++++        ++      ++            ++          ++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/ref-self-multi.rs:23:63
+   |
+LL |     fn ref_wrap_ref_Self(self: &Wrap<&Self, u32>, f: &u32) -> &u32 {
+   |                                -----------------     ----     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn ref_wrap_ref_Self<'a>(self: &'a Wrap<&'a Self, u32>, f: &'a u32) -> &'a u32 {
+   |                         ++++        ++       ++                 ++          ++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
diff --git a/tests/ui/self/elision/ref-self.fixed b/tests/ui/self/elision/ref-self.fixed
index 8bf5a0bb223..784ccb9efe2 100644
--- a/tests/ui/self/elision/ref-self.fixed
+++ b/tests/ui/self/elision/ref-self.fixed
@@ -1,4 +1,6 @@
 //@ run-rustfix
+//@ edition:2018
+
 #![feature(arbitrary_self_types)]
 #![allow(non_snake_case, dead_code)]
 
@@ -56,6 +58,11 @@ impl Struct {
         f
         //~^ ERROR lifetime may not live long enough
     }
+
+    fn ref_box_Self<'a>(self: &Box<Self>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
 }
 
 fn main() {}
diff --git a/tests/ui/self/elision/ref-self.rs b/tests/ui/self/elision/ref-self.rs
index 4b4b8aa5b51..dbe441879cc 100644
--- a/tests/ui/self/elision/ref-self.rs
+++ b/tests/ui/self/elision/ref-self.rs
@@ -1,4 +1,6 @@
 //@ run-rustfix
+//@ edition:2018
+
 #![feature(arbitrary_self_types)]
 #![allow(non_snake_case, dead_code)]
 
@@ -56,6 +58,11 @@ impl Struct {
         f
         //~^ ERROR lifetime may not live long enough
     }
+
+    fn ref_box_Self(self: &Box<Self>, f: &u32) -> &u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
 }
 
 fn main() {}
diff --git a/tests/ui/self/elision/ref-self.stderr b/tests/ui/self/elision/ref-self.stderr
index c4ec8c55a00..64e7bfc1bb0 100644
--- a/tests/ui/self/elision/ref-self.stderr
+++ b/tests/ui/self/elision/ref-self.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:24:9
+  --> $DIR/ref-self.rs:26:9
    |
 LL |     fn ref_self(&self, f: &u32) -> &u32 {
    |                 -         - let's call the lifetime of this reference `'1`
@@ -14,7 +14,7 @@ LL |     fn ref_self<'a>(&self, f: &'a u32) -> &'a u32 {
    |                ++++            ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:31:9
+  --> $DIR/ref-self.rs:33:9
    |
 LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                       -         - let's call the lifetime of this reference `'1`
@@ -29,7 +29,7 @@ LL |     fn ref_Self<'a>(self: &Self, f: &'a u32) -> &'a u32 {
    |                ++++                  ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:36:9
+  --> $DIR/ref-self.rs:38:9
    |
 LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -44,7 +44,7 @@ LL |     fn box_ref_Self<'a>(self: Box<&Self>, f: &'a u32) -> &'a u32 {
    |                    ++++                       ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:41:9
+  --> $DIR/ref-self.rs:43:9
    |
 LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -59,7 +59,7 @@ LL |     fn pin_ref_Self<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 {
    |                    ++++                       ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:46:9
+  --> $DIR/ref-self.rs:48:9
    |
 LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                       -           - let's call the lifetime of this reference `'1`
@@ -74,7 +74,7 @@ LL |     fn box_box_ref_Self<'a>(self: Box<Box<&Self>>, f: &'a u32) -> &'a u32 {
    |                        ++++                            ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:51:9
+  --> $DIR/ref-self.rs:53:9
    |
 LL |     fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                       -           - let's call the lifetime of this reference `'1`
@@ -89,7 +89,7 @@ LL |     fn box_pin_ref_Self<'a>(self: Box<Pin<&Self>>, f: &'a u32) -> &'a u32 {
    |                        ++++                            ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:56:9
+  --> $DIR/ref-self.rs:58:9
    |
 LL |     fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
    |                                      -                - let's call the lifetime of this reference `'1`
@@ -103,5 +103,20 @@ help: consider introducing a named lifetime parameter and update trait if needed
 LL |     fn wrap_ref_Self_Self<'a>(self: Wrap<&Self, Self>, f: &'a u8) -> &'a u8 {
    |                          ++++                              ++         ++
 
-error: aborting due to 7 previous errors
+error: lifetime may not live long enough
+  --> $DIR/ref-self.rs:63:9
+   |
+LL |     fn ref_box_Self(self: &Box<Self>, f: &u32) -> &u32 {
+   |                           -              - let's call the lifetime of this reference `'1`
+   |                           |
+   |                           let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn ref_box_Self<'a>(self: &Box<Self>, f: &'a u32) -> &'a u32 {
+   |                    ++++                       ++          ++
+
+error: aborting due to 8 previous errors