about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/infer/error_reporting/anon_anon_conflict.rs222
-rw-r--r--src/librustc/infer/error_reporting/named_anon_conflict.rs84
-rw-r--r--src/librustc/infer/error_reporting/util.rs73
-rw-r--r--src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr23
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-2.stderr2
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-3.rs5
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-3.stderr20
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr20
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.rs19
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr10
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.rs19
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr12
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.rs19
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr12
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.rs (renamed from src/test/ui/lifetime-errors/ex3-both-anon-regions-4.rs)11
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr10
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.rs17
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr12
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.rs17
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr12
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.rs17
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr10
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.rs20
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr10
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs22
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr23
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.rs22
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr23
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.rs18
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr10
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions.rs2
-rw-r--r--src/test/ui/lifetime-errors/ex3-both-anon-regions.stderr2
32 files changed, 621 insertions, 177 deletions
diff --git a/src/librustc/infer/error_reporting/anon_anon_conflict.rs b/src/librustc/infer/error_reporting/anon_anon_conflict.rs
index 2e910968818..3821bf766b9 100644
--- a/src/librustc/infer/error_reporting/anon_anon_conflict.rs
+++ b/src/librustc/infer/error_reporting/anon_anon_conflict.rs
@@ -27,65 +27,83 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     //    { x.push(y); }.
     // The example gives
     // fn foo(x: &mut Vec<&u8>, y: &u8) {
-    //                    ---      --- these references must have the same lifetime
+    //                    ---      --- these references are declared with different lifetimes...
     //            x.push(y);
-    //            ^ data from `y` flows into `x` here
-    // It will later be extended to trait objects and structs.
+    //            ^ ...but data from `y` flows into `x` here
+    // It has been extended for the case of structs too.
+    // Consider the example
+    // struct Ref<'a> { x: &'a u32 }
+    // fn foo(mut x: Vec<Ref>, y: Ref) {
+    //                   ---      --- these structs are declared with different lifetimes...
+    //               x.push(y);
+    //               ^ ...but data from `y` flows into `x` here
+    // }
+    // It will later be extended to trait objects.
     pub fn try_report_anon_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
-
         let (span, sub, sup) = match *error {
             ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
             _ => return false, // inapplicable
         };
 
         // Determine whether the sub and sup consist of both anonymous (elided) regions.
-        let (ty1, ty2) = if self.is_suitable_anonymous_region(sup).is_some() &&
-                            self.is_suitable_anonymous_region(sub).is_some() {
-            if let (Some(anon_reg1), Some(anon_reg2)) =
-                (self.is_suitable_anonymous_region(sup), self.is_suitable_anonymous_region(sub)) {
-                let ((_, br1), (_, br2)) = (anon_reg1, anon_reg2);
-                if self.find_anon_type(sup, &br1).is_some() &&
-                   self.find_anon_type(sub, &br2).is_some() {
-                    (self.find_anon_type(sup, &br1).unwrap(),
-                     self.find_anon_type(sub, &br2).unwrap())
+        let (ty_sup, ty_sub, scope_def_id_sup, scope_def_id_sub, bregion_sup, bregion_sub) =
+            if let (Some(anon_reg_sup), Some(anon_reg_sub)) =
+                (self.is_suitable_anonymous_region(sup, true),
+                 self.is_suitable_anonymous_region(sub, true)) {
+                let ((def_id_sup, br_sup), (def_id_sub, br_sub)) = (anon_reg_sup, anon_reg_sub);
+                if let (Some(anonarg_sup), Some(anonarg_sub)) =
+                    (self.find_anon_type(sup, &br_sup), self.find_anon_type(sub, &br_sub)) {
+                    (anonarg_sup, anonarg_sub, def_id_sup, def_id_sub, br_sup, br_sub)
                 } else {
                     return false;
                 }
             } else {
                 return false;
-            }
-        } else {
-            return false; // inapplicable
-        };
+            };
 
-        if let (Some(sup_arg), Some(sub_arg)) =
+        let (label1, label2) = if let (Some(sup_arg), Some(sub_arg)) =
             (self.find_arg_with_anonymous_region(sup, sup),
              self.find_arg_with_anonymous_region(sub, sub)) {
-            let ((anon_arg1, _, _, _), (anon_arg2, _, _, _)) = (sup_arg, sub_arg);
 
-            let span_label_var1 = if let Some(simple_name) = anon_arg1.pat.simple_name() {
-                format!(" from `{}` ", simple_name)
-            } else {
-                format!(" ")
-            };
+            let ((anon_arg_sup, _, _, is_first_sup), (anon_arg_sub, _, _, is_first_sub)) =
+                (sup_arg, sub_arg);
+            if self.is_self_anon(is_first_sup, scope_def_id_sup) ||
+               self.is_self_anon(is_first_sub, scope_def_id_sub) {
+                return false;
+            }
+
+            if self.is_return_type_anon(scope_def_id_sup, bregion_sup) ||
+               self.is_return_type_anon(scope_def_id_sub, bregion_sub) {
+                return false;
+            }
 
-            let span_label_var2 = if let Some(simple_name) = anon_arg2.pat.simple_name() {
-                format!(" into `{}` ", simple_name)
+            if anon_arg_sup == anon_arg_sub {
+                (format!(" with one lifetime"), format!(" into the other"))
             } else {
-                format!(" ")
-            };
+                let span_label_var1 = if let Some(simple_name) = anon_arg_sup.pat.simple_name() {
+                    format!(" from `{}`", simple_name)
+                } else {
+                    format!("")
+                };
+
+                let span_label_var2 = if let Some(simple_name) = anon_arg_sub.pat.simple_name() {
+                    format!(" into `{}`", simple_name)
+                } else {
+                    format!("")
+                };
 
-            struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch")
-                .span_label(ty1.span,
-                            format!("these references are not declared with the same lifetime..."))
-                .span_label(ty2.span, format!(""))
-                .span_label(span,
-                            format!("...but data{}flows{}here", span_label_var1, span_label_var2))
-                .emit();
+                (span_label_var1, span_label_var2)
+            }
         } else {
             return false;
-        }
+        };
 
+        struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch")
+            .span_label(ty_sup.span,
+                        format!("these two types are declared with different lifetimes..."))
+            .span_label(ty_sub.span, format!(""))
+            .span_label(span, format!("...but data{} flows{} here", label1, label2))
+            .emit();
         return true;
     }
 
@@ -94,7 +112,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// contains the anonymous type.
     ///
     /// # Arguments
-    ///
     /// region - the anonymous region corresponding to the anon_anon conflict
     /// br - the bound region corresponding to the above region which is of type `BrAnon(_)`
     ///
@@ -105,8 +122,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// ```
     /// The function returns the nested type corresponding to the anonymous region
     /// for e.g. `&u8` and Vec<`&u8`.
-    fn find_anon_type(&self, region: Region<'tcx>, br: &ty::BoundRegion) -> Option<&hir::Ty> {
-        if let Some(anon_reg) = self.is_suitable_anonymous_region(region) {
+    pub fn find_anon_type(&self, region: Region<'tcx>, br: &ty::BoundRegion) -> Option<&hir::Ty> {
+        if let Some(anon_reg) = self.is_suitable_anonymous_region(region, true) {
             let (def_id, _) = anon_reg;
             if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
                 let ret_ty = self.tcx.type_of(def_id);
@@ -117,19 +134,33 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                        .inputs
                                        .iter()
                                        .filter_map(|arg| {
-                                let mut nested_visitor = FindNestedTypeVisitor {
-                                    infcx: &self,
-                                    hir_map: &self.tcx.hir,
-                                    bound_region: *br,
-                                    found_type: None,
-                                };
-                                nested_visitor.visit_ty(&**arg);
-                                if nested_visitor.found_type.is_some() {
-                                    nested_visitor.found_type
-                                } else {
-                                    None
-                                }
-                            })
+                                                       self.find_component_for_bound_region(&**arg,
+                                                                                            br)
+                                                   })
+                                       .next();
+                        }
+                    } else if let hir_map::NodeTraitItem(it) = self.tcx.hir.get(node_id) {
+                        if let hir::TraitItemKind::Method(ref fndecl, _) = it.node {
+                            return fndecl
+                                       .decl
+                                       .inputs
+                                       .iter()
+                                       .filter_map(|arg| {
+                                                       self.find_component_for_bound_region(&**arg,
+                                                                                            br)
+                                                   })
+                                       .next();
+                        }
+                    } else if let hir_map::NodeImplItem(it) = self.tcx.hir.get(node_id) {
+                        if let hir::ImplItemKind::Method(ref fndecl, _) = it.node {
+                            return fndecl
+                                       .decl
+                                       .inputs
+                                       .iter()
+                                       .filter_map(|arg| {
+                                                       self.find_component_for_bound_region(&**arg,
+                                                                                            br)
+                                                   })
                                        .next();
                         }
                     }
@@ -138,6 +169,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
         None
     }
+
+    // This method creates a FindNestedTypeVisitor which returns the type corresponding
+    // to the anonymous region.
+    fn find_component_for_bound_region(&self,
+                                       arg: &'gcx hir::Ty,
+                                       br: &ty::BoundRegion)
+                                       -> Option<(&'gcx hir::Ty)> {
+        let mut nested_visitor = FindNestedTypeVisitor {
+            infcx: &self,
+            hir_map: &self.tcx.hir,
+            bound_region: *br,
+            found_type: None,
+        };
+        nested_visitor.visit_ty(arg);
+        nested_visitor.found_type
+    }
 }
 
 // The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
@@ -176,8 +223,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
             hir::TyRptr(ref lifetime, _) => {
                 match self.infcx.tcx.named_region_map.defs.get(&lifetime.id) {
                     // the lifetime of the TyRptr
-                    Some(&rl::Region::LateBoundAnon(debuijn_index, anon_index)) => {
-                        if debuijn_index.depth == 1 && anon_index == br_index {
+                    Some(&rl::Region::LateBoundAnon(debruijn_index, anon_index)) => {
+                        if debruijn_index.depth == 1 && anon_index == br_index {
                             self.found_type = Some(arg);
                             return; // we can stop visiting now
                         }
@@ -191,6 +238,20 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
                     }
                 }
             }
+            // Checks if it is of type `hir::TyPath` which corresponds to a struct.
+            hir::TyPath(_) => {
+                let subvisitor = &mut TyPathVisitor {
+                                          infcx: self.infcx,
+                                          found_it: false,
+                                          bound_region: self.bound_region,
+                                          hir_map: self.hir_map,
+                                      };
+                intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty,
+                // this will visit only outermost type
+                if subvisitor.found_it {
+                    self.found_type = Some(arg);
+                }
+            }
             _ => {}
         }
         // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
@@ -198,3 +259,56 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
         intravisit::walk_ty(self, arg);
     }
 }
+
+// The visitor captures the corresponding `hir::Ty` of the anonymous region
+// in the case of structs ie. `hir::TyPath`.
+// This visitor would be invoked for each lifetime corresponding to a struct,
+// and would walk the types like Vec<Ref> in the above example and Ref looking for the HIR
+// where that lifetime appears. This allows us to highlight the
+// specific part of the type in the error message.
+struct TyPathVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    hir_map: &'a hir::map::Map<'gcx>,
+    found_it: bool,
+    bound_region: ty::BoundRegion,
+}
+
+impl<'a, 'gcx, 'tcx> Visitor<'gcx> for TyPathVisitor<'a, 'gcx, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
+        NestedVisitorMap::OnlyBodies(&self.hir_map)
+    }
+
+    fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
+        let br_index = match self.bound_region {
+            ty::BrAnon(index) => index,
+            _ => return,
+        };
+
+        match self.infcx.tcx.named_region_map.defs.get(&lifetime.id) {
+            // the lifetime of the TyPath!
+            Some(&rl::Region::LateBoundAnon(debruijn_index, anon_index)) => {
+                if debruijn_index.depth == 1 && anon_index == br_index {
+                    self.found_it = true;
+                }
+            }
+            Some(&rl::Region::Static) |
+            Some(&rl::Region::EarlyBound(_, _)) |
+            Some(&rl::Region::LateBound(_, _)) |
+            Some(&rl::Region::Free(_, _)) |
+            None => {
+                debug!("no arg found");
+            }
+        }
+    }
+
+    fn visit_ty(&mut self, arg: &'gcx hir::Ty) {
+        // ignore nested types
+        //
+        // If you have a type like `Foo<'a, &Ty>` we
+        // are only interested in the immediate lifetimes ('a).
+        //
+        // Making `visit_ty` empty will ignore the `&Ty` embedded
+        // inside, it will get reached by the outer visitor.
+        debug!("`Ty` corresponding to a struct is {:?}", arg);
+    }
+}
diff --git a/src/librustc/infer/error_reporting/named_anon_conflict.rs b/src/librustc/infer/error_reporting/named_anon_conflict.rs
index 491079a1f92..f46855502ea 100644
--- a/src/librustc/infer/error_reporting/named_anon_conflict.rs
+++ b/src/librustc/infer/error_reporting/named_anon_conflict.rs
@@ -11,7 +11,6 @@
 //! Error Reporting for Anonymous Region Lifetime Errors
 //! where one region is named and the other is anonymous.
 use infer::InferCtxt;
-use ty;
 use infer::region_inference::RegionResolutionError::*;
 use infer::region_inference::RegionResolutionError;
 
@@ -31,63 +30,42 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         // only introduced anonymous regions in parameters) as well as a
         // version new_ty of its type where the anonymous region is replaced
         // with the named one.
-        let (named, (arg, new_ty, br, is_first), (scope_def_id, _)) =
-            if sub.is_named_region() && self.is_suitable_anonymous_region(sup).is_some() {
-                (sub,
-                 self.find_arg_with_anonymous_region(sup, sub).unwrap(),
-                 self.is_suitable_anonymous_region(sup).unwrap())
-            } else if sup.is_named_region() && self.is_suitable_anonymous_region(sub).is_some() {
-                (sup,
-                 self.find_arg_with_anonymous_region(sub, sup).unwrap(),
-                 self.is_suitable_anonymous_region(sub).unwrap())
-            } else {
-                return false; // inapplicable
-            };
-
-        // Here, we check for the case where the anonymous region
-        // is in the return type.
-        // FIXME(#42703) - Need to handle certain cases here.
-        let ret_ty = self.tcx.type_of(scope_def_id);
-        match ret_ty.sty {
-            ty::TyFnDef(_, _) => {
-                let sig = ret_ty.fn_sig(self.tcx);
-                let late_bound_regions = self.tcx
-                    .collect_referenced_late_bound_regions(&sig.output());
-                if late_bound_regions.iter().any(|r| *r == br) {
-                    return false;
-                }
-            }
-            _ => {}
-        }
+        let (named, (arg, new_ty, br, is_first), (scope_def_id, _)) = if
+            sub.is_named_region() && self.is_suitable_anonymous_region(sup, false).is_some() {
+            (sub,
+             self.find_arg_with_anonymous_region(sup, sub).unwrap(),
+             self.is_suitable_anonymous_region(sup, false).unwrap())
+        } else if
+            sup.is_named_region() && self.is_suitable_anonymous_region(sub, false).is_some() {
+            (sup,
+             self.find_arg_with_anonymous_region(sub, sup).unwrap(),
+             self.is_suitable_anonymous_region(sub, false).unwrap())
+        } else {
+            return false; // inapplicable
+        };
 
-        // Here we check for the case where anonymous region
-        // corresponds to self and if yes, we display E0312.
-        // FIXME(#42700) - Need to format self properly to
-        // enable E0621 for it.
-        if is_first &&
-           self.tcx
-               .opt_associated_item(scope_def_id)
-               .map(|i| i.method_has_self_argument)
-               .unwrap_or(false) {
+        if self.is_return_type_anon(scope_def_id, br) || self.is_self_anon(is_first, scope_def_id) {
             return false;
-        }
-
-        let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() {
-            (format!("the type of `{}`", simple_name), format!("the type of `{}`", simple_name))
         } else {
-            ("parameter type".to_owned(), "type".to_owned())
-        };
 
-        struct_span_err!(self.tcx.sess,
-                         span,
-                         E0621,
-                         "explicit lifetime required in {}",
-                         error_var)
-                .span_label(arg.pat.span,
-                            format!("consider changing {} to `{}`", span_label_var, new_ty))
-                .span_label(span, format!("lifetime `{}` required", named))
-                .emit();
+            let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() {
+                (format!("the type of `{}`", simple_name), format!("the type of `{}`", simple_name))
+            } else {
+                ("parameter type".to_owned(), "type".to_owned())
+            };
 
+            struct_span_err!(self.tcx.sess,
+                             span,
+                             E0621,
+                             "explicit lifetime required in {}",
+                             error_var)
+                    .span_label(arg.pat.span,
+                                format!("consider changing {} to `{}`", span_label_var, new_ty))
+                    .span_label(span, format!("lifetime `{}` required", named))
+                    .emit();
+
+
+        }
         return true;
     }
 }
diff --git a/src/librustc/infer/error_reporting/util.rs b/src/librustc/infer/error_reporting/util.rs
index 14fe8e699c7..21a6e8e050a 100644
--- a/src/librustc/infer/error_reporting/util.rs
+++ b/src/librustc/infer/error_reporting/util.rs
@@ -79,22 +79,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     // This method returns whether the given Region is Anonymous
     // and returns the DefId and the BoundRegion corresponding to the given region.
+    // The is_anon_anon is set true when we are dealing with cases where
+    // both the regions are anonymous i.e. E0623.
     pub fn is_suitable_anonymous_region(&self,
-                                        region: Region<'tcx>)
+                                        region: Region<'tcx>,
+                                        is_anon_anon: bool)
                                         -> Option<(DefId, ty::BoundRegion)> {
         if let ty::ReFree(ref free_region) = *region {
-            if let ty::BrAnon(..) = free_region.bound_region{
-                    let anonymous_region_binding_scope = free_region.scope;
-                    let node_id = self.tcx
-                        .hir
-                        .as_local_node_id(anonymous_region_binding_scope)
-                        .unwrap();
-                    match self.tcx.hir.find(node_id) {
-                        Some(hir_map::NodeItem(..)) |
-                        Some(hir_map::NodeTraitItem(..)) => {
-                            // Success -- proceed to return Some below
-                        }
-                        Some(hir_map::NodeImplItem(..)) => {
+            if let ty::BrAnon(..) = free_region.bound_region {
+                let anonymous_region_binding_scope = free_region.scope;
+                let node_id = self.tcx
+                    .hir
+                    .as_local_node_id(anonymous_region_binding_scope)
+                    .unwrap();
+                match self.tcx.hir.find(node_id) {
+                    Some(hir_map::NodeItem(..)) |
+                    Some(hir_map::NodeTraitItem(..)) => {
+                        // Success -- proceed to return Some below
+                    }
+                    Some(hir_map::NodeImplItem(..)) => {
+                        if !is_anon_anon {
                             let container_id = self.tcx
                                 .associated_item(anonymous_region_binding_scope)
                                 .container
@@ -108,13 +112,48 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                 // FIXME(#42706) -- in some cases, we could do better here.
                                 return None;
                             }
+                        } else {
                         }
-                        _ => return None, // inapplicable
-                        // we target only top-level functions
                     }
-                    return Some((anonymous_region_binding_scope, free_region.bound_region));
+                    _ => return None, // inapplicable
+                    // we target only top-level functions
                 }
+                return Some((anonymous_region_binding_scope, free_region.bound_region));
             }
-            None
         }
+        None
+    }
+
+    // Here, we check for the case where the anonymous region
+    // is in the return type.
+    // FIXME(#42703) - Need to handle certain cases here.
+    pub fn is_return_type_anon(&self, scope_def_id: DefId, br: ty::BoundRegion) -> bool {
+        let ret_ty = self.tcx.type_of(scope_def_id);
+        match ret_ty.sty {
+            ty::TyFnDef(_, _) => {
+                let sig = ret_ty.fn_sig(self.tcx);
+                let late_bound_regions = self.tcx
+                    .collect_referenced_late_bound_regions(&sig.output());
+                if late_bound_regions.iter().any(|r| *r == br) {
+                    return true;
+                }
+            }
+            _ => {}
+        }
+        false
+    }
+    // Here we check for the case where anonymous region
+    // corresponds to self and if yes, we display E0312.
+    // FIXME(#42700) - Need to format self properly to
+    // enable E0621 for it.
+    pub fn is_self_anon(&self, is_first: bool, scope_def_id: DefId) -> bool {
+        if is_first &&
+           self.tcx
+               .opt_associated_item(scope_def_id)
+               .map(|i| i.method_has_self_argument)
+               .unwrap_or(false) {
+            return true;
+        }
+        false
+    }
 }
diff --git a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr
index 6764c58f4bb..1ee00997997 100644
--- a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr
+++ b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr
@@ -1,25 +1,10 @@
-error[E0308]: mismatched types
+error[E0623]: lifetime mismatch
   --> $DIR/ex2b-push-no-existing-names.rs:16:12
    |
+15 | fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
+   |                    --------      -------- these two types are declared with different lifetimes...
 16 |     x.push(y);
-   |            ^ lifetime mismatch
-   |
-   = note: expected type `Ref<'_, _>`
-              found type `Ref<'_, _>`
-note: the anonymous lifetime #3 defined on the function body at 15:1...
-  --> $DIR/ex2b-push-no-existing-names.rs:15:1
-   |
-15 | / fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
-16 | |     x.push(y);
-17 | | }
-   | |_^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 15:1
-  --> $DIR/ex2b-push-no-existing-names.rs:15:1
-   |
-15 | / fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
-16 | |     x.push(y);
-17 | | }
-   | |_^
+   |            ^ ...but data from `y` flows into `x` here
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.stderr
index 4c878f3c0dc..74a40c87c2f 100644
--- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.stderr
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.stderr
@@ -2,7 +2,7 @@ error[E0623]: lifetime mismatch
   --> $DIR/ex3-both-anon-regions-2.rs:12:9
    |
 11 | fn foo((v, w): (&u8, &u8), x: &u8) {
-   |                 ---           --- these references are not declared with the same lifetime...
+   |                 ---           --- these two types are declared with different lifetimes...
 12 |     v = x;
    |         ^ ...but data from `x` flows here
 
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.rs
index 7bd5ebf805f..51271243bdf 100644
--- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.rs
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.rs
@@ -8,8 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn foo((v, w): (&u8, &u8), (x, y): (&u8, &u8)) {
-    v = x;
+fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
+    z.push((x,y));
 }
 
 fn main() { }
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.stderr
index 08506b8befa..898866c75f2 100644
--- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.stderr
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.stderr
@@ -1,10 +1,18 @@
 error[E0623]: lifetime mismatch
-  --> $DIR/ex3-both-anon-regions-3.rs:12:9
+  --> $DIR/ex3-both-anon-regions-3.rs:12:13
    |
-11 | fn foo((v, w): (&u8, &u8), (x, y): (&u8, &u8)) {
-   |                 ---                 --- these references are not declared with the same lifetime...
-12 |     v = x;
-   |         ^ ...but data flows here
+11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
+   |                     ---                 --- these two types are declared with different lifetimes...
+12 |     z.push((x,y));
+   |             ^ ...but data flows into `z` here
 
-error: aborting due to previous error
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-3.rs:12:15
+   |
+11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
+   |                         ---                  --- these two types are declared with different lifetimes...
+12 |     z.push((x,y));
+   |               ^ ...but data flows into `z` here
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr
deleted file mode 100644
index 9c2630fc811..00000000000
--- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0601]: main function not found
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ex3-both-anon-regions-4.rs:12:13
-   |
-11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
-   |                     ---                 --- these references are not declared with the same lifetime...
-12 |     z.push((x,y));
-   |             ^ ...but data flows into `z` here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ex3-both-anon-regions-4.rs:12:15
-   |
-11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
-   |                         ---                  --- these references are not declared with the same lifetime...
-12 |     z.push((x,y));
-   |               ^ ...but data flows into `z` here
-
-error: aborting due to 3 previous errors
-
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.rs
new file mode 100644
index 00000000000..2fbf31aead5
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+struct Ref<'a, 'b> {
+    a: &'a u32,
+    b: &'b u32,
+}
+
+fn foo(mut x: Ref, y: Ref) {
+    x.b = y.b;
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr
new file mode 100644
index 00000000000..26f31defc9e
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr
@@ -0,0 +1,10 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-both-are-structs-2.rs:16:11
+   |
+15 | fn foo(mut x: Ref, y: Ref) {
+   |               ---     --- these two types are declared with different lifetimes...
+16 |     x.b = y.b;
+   |           ^^^ ...but data from `y` flows into `x` here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.rs
new file mode 100644
index 00000000000..120a7ca74ae
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+struct Ref<'a, 'b> {
+    a: &'a u32,
+    b: &'b u32,
+}
+
+fn foo(mut x: Ref) {
+    x.a = x.b;
+}
+
+fn main() {}
\ No newline at end of file
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr
new file mode 100644
index 00000000000..5ec4511372a
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr
@@ -0,0 +1,12 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-both-are-structs-3.rs:16:11
+   |
+15 | fn foo(mut x: Ref) {
+   |               ---
+   |               |
+   |               these two types are declared with different lifetimes...
+16 |     x.a = x.b;
+   |           ^^^ ...but data with one lifetime flows into the other here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.rs
new file mode 100644
index 00000000000..606e611865f
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+struct Ref<'a, 'b> {
+    a: &'a u32,
+    b: &'b u32,
+}
+
+fn foo(mut x: Ref) {
+    x.a = x.b;
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr
new file mode 100644
index 00000000000..2ef1cd507f1
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.stderr
@@ -0,0 +1,12 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-both-are-structs-4.rs:16:11
+   |
+15 | fn foo(mut x: Ref) {
+   |               ---
+   |               |
+   |               these two types are declared with different lifetimes...
+16 |     x.a = x.b;
+   |           ^^^ ...but data with one lifetime flows into the other here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.rs
index fdb010a04f4..67ba8ee532a 100644
--- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.rs
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -7,7 +7,12 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+struct Ref<'a> {
+    x: &'a u32,
+}
 
-fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
-    z.push((x,y));
+fn foo(mut x: Vec<Ref>, y: Ref) {
+    x.push(y);
 }
+
+fn main() {}
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr
new file mode 100644
index 00000000000..6ad795400b3
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr
@@ -0,0 +1,10 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-both-are-structs.rs:15:12
+   |
+14 | fn foo(mut x: Vec<Ref>, y: Ref) {
+   |                   ---      --- these two types are declared with different lifetimes...
+15 |     x.push(y);
+   |            ^ ...but data from `y` flows into `x` here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.rs
new file mode 100644
index 00000000000..a8b1f53fc98
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.rs
@@ -0,0 +1,17 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Ref<'a, 'b> { a: &'a u32, b: &'b u32 }
+
+fn foo(mut x: Ref, y: &u32) {
+    y = x.b;
+}
+
+fn main() { }
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr
new file mode 100644
index 00000000000..31c7ebf6504
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr
@@ -0,0 +1,12 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:14:9
+   |
+13 | fn foo(mut x: Ref, y: &u32) {
+   |               ---     ----
+   |               |
+   |               these two types are declared with different lifetimes...
+14 |     y = x.b;
+   |         ^^^ ...but data from `x` flows into `y` here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.rs
new file mode 100644
index 00000000000..026b4e90c4e
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.rs
@@ -0,0 +1,17 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Ref<'a, 'b> { a: &'a u32, b: &'b u32 }
+
+fn foo(mut y: Ref, x: &u32) {
+    x = y.b;
+}
+
+fn main() { }
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr
new file mode 100644
index 00000000000..8f1cff9c4a8
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr
@@ -0,0 +1,12 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-one-is-struct-3.rs:14:9
+   |
+13 | fn foo(mut y: Ref, x: &u32) {
+   |               ---     ----
+   |               |
+   |               these two types are declared with different lifetimes...
+14 |     x = y.b;
+   |         ^^^ ...but data from `y` flows into `x` here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.rs
new file mode 100644
index 00000000000..4933dbb7e7a
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.rs
@@ -0,0 +1,17 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Ref<'a, 'b> { a: &'a u32, b: &'b u32 }
+
+fn foo(mut y: Ref, x: &u32) {
+    y.b = x;
+}
+
+fn main() { }
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr
new file mode 100644
index 00000000000..40f026bcb1b
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr
@@ -0,0 +1,10 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-one-is-struct-4.rs:14:11
+   |
+13 | fn foo(mut y: Ref, x: &u32) {
+   |               ---     ---- these two types are declared with different lifetimes...
+14 |     y.b = x;
+   |           ^ ...but data from `x` flows into `y` here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.rs
new file mode 100644
index 00000000000..e1594b1a277
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.rs
@@ -0,0 +1,20 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Ref<'a, 'b> {
+    a: &'a u32,
+    b: &'b u32,
+}
+
+fn foo(mut x: Ref, y: &u32) {
+    x.b = y;
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr
new file mode 100644
index 00000000000..bb7b9ea6843
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr
@@ -0,0 +1,10 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-one-is-struct.rs:17:11
+   |
+16 | fn foo(mut x: Ref, y: &u32) {
+   |               ---     ---- these two types are declared with different lifetimes...
+17 |     x.b = y;
+   |           ^ ...but data from `y` flows into `x` here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs
new file mode 100644
index 00000000000..0dc257ac092
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs
@@ -0,0 +1,22 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo {
+  field: i32
+}
+
+impl Foo {
+  fn foo<'a>(&self, x: &i32) -> &i32 {
+    x
+  }
+}
+
+fn main() { }
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr
new file mode 100644
index 00000000000..890f9b311e7
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr
@@ -0,0 +1,23 @@
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:17:5
+   |
+17 |     x
+   |     ^
+   |
+note: ...the reference is valid for the anonymous lifetime #1 defined on the method body at 16:3...
+  --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:16:3
+   |
+16 | /   fn foo<'a>(&self, x: &i32) -> &i32 {
+17 | |     x
+18 | |   }
+   | |___^
+note: ...but the borrowed content is only valid for the anonymous lifetime #2 defined on the method body at 16:3
+  --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:16:3
+   |
+16 | /   fn foo<'a>(&self, x: &i32) -> &i32 {
+17 | |     x
+18 | |   }
+   | |___^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.rs
new file mode 100644
index 00000000000..0940ce15d1e
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.rs
@@ -0,0 +1,22 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo {
+    field: i32,
+}
+
+impl Foo {
+    fn foo<'a>(&self, x: &Foo) -> &Foo {
+        if true { x } else { self }
+    }
+}
+
+fn main() {}
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr
new file mode 100644
index 00000000000..43f00c32c62
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr
@@ -0,0 +1,23 @@
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/ex3-both-anon-regions-self-is-anon.rs:17:19
+   |
+17 |         if true { x } else { self }
+   |                   ^
+   |
+note: ...the reference is valid for the anonymous lifetime #1 defined on the method body at 16:5...
+  --> $DIR/ex3-both-anon-regions-self-is-anon.rs:16:5
+   |
+16 | /     fn foo<'a>(&self, x: &Foo) -> &Foo {
+17 | |         if true { x } else { self }
+18 | |     }
+   | |_____^
+note: ...but the borrowed content is only valid for the anonymous lifetime #2 defined on the method body at 16:5
+  --> $DIR/ex3-both-anon-regions-self-is-anon.rs:16:5
+   |
+16 | /     fn foo<'a>(&self, x: &Foo) -> &Foo {
+17 | |         if true { x } else { self }
+18 | |     }
+   | |_____^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.rs
new file mode 100644
index 00000000000..3a7ba415c0d
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.rs
@@ -0,0 +1,18 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+trait Foo {
+    fn foo<'a>(x: &mut Vec<&u8>, y: &u8);
+}
+impl Foo for () {
+    fn foo(x: &mut Vec<&u8>, y: &u8) {
+        x.push(y);
+    }
+}
+fn main() {}
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr
new file mode 100644
index 00000000000..9591df8e8aa
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr
@@ -0,0 +1,10 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-using-impl-items.rs:15:16
+   |
+14 |     fn foo(x: &mut Vec<&u8>, y: &u8) {
+   |                        ---      --- these two types are declared with different lifetimes...
+15 |         x.push(y);
+   |                ^ ...but data from `y` flows into `x` here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions.rs
index 9ebff511876..be48d07b94e 100644
--- a/src/test/ui/lifetime-errors/ex3-both-anon-regions.rs
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions.stderr
index a183d1fffc0..d3291063859 100644
--- a/src/test/ui/lifetime-errors/ex3-both-anon-regions.stderr
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions.stderr
@@ -2,7 +2,7 @@ error[E0623]: lifetime mismatch
   --> $DIR/ex3-both-anon-regions.rs:12:12
    |
 11 | fn foo(x: &mut Vec<&u8>, y: &u8) {
-   |                    ---      --- these references are not declared with the same lifetime...
+   |                    ---      --- these two types are declared with different lifetimes...
 12 |     x.push(y);
    |            ^ ...but data from `y` flows into `x` here