about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/infer/error_reporting/anon_anon_conflict.rs240
-rw-r--r--src/librustc/infer/error_reporting/mod.rs4
-rw-r--r--src/librustc/infer/error_reporting/named_anon_conflict.rs69
-rw-r--r--src/librustc/infer/error_reporting/util.rs156
-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.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.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
29 files changed, 624 insertions, 204 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..c80ce3c96f1 100644
--- a/src/librustc/infer/error_reporting/anon_anon_conflict.rs
+++ b/src/librustc/infer/error_reporting/anon_anon_conflict.rs
@@ -27,65 +27,84 @@ 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())
-                } else {
-                    return false;
-                }
-            } else {
-                return false;
-            }
-        } else {
-            return false; // inapplicable
-        };
+        let anon_reg_sup = or_false!(self.is_suitable_anonymous_region(sup));
 
-        if let (Some(sup_arg), Some(sub_arg)) =
+        let anon_reg_sub = or_false!(self.is_suitable_anonymous_region(sub));
+        let scope_def_id_sup = anon_reg_sup.def_id;
+        let bregion_sup = anon_reg_sup.boundregion;
+        let scope_def_id_sub = anon_reg_sub.def_id;
+        let bregion_sub = anon_reg_sub.boundregion;
+
+        let ty_sup = or_false!(self.find_anon_type(sup, &bregion_sup));
+
+        let ty_sub = or_false!(self.find_anon_type(sub, &bregion_sub));
+
+        let (main_label, 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.arg, sup_arg.is_first, sub_arg.arg, sub_arg.is_first);
+            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;
+            }
 
-            let span_label_var2 = if let Some(simple_name) = anon_arg2.pat.simple_name() {
-                format!(" into `{}` ", simple_name)
+            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;
+            }
+
+            if anon_arg_sup == anon_arg_sub {
+                (format!("this type was declared with multiple lifetimes..."),
+                 format!(" with one lifetime"),
+                 format!(" into the other"))
             } 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();
+                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!("")
+                };
+
+                let span_label =
+                    format!("these two types are declared with different lifetimes...",);
+
+                (span_label, span_label_var1, span_label_var2)
+            }
         } else {
             return false;
-        }
+        };
 
+        struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch")
+            .span_label(ty_sup.span, main_label)
+            .span_label(ty_sub.span, format!(""))
+            .span_label(span, format!("...but data{} flows{} here", label1, label2))
+            .emit();
         return true;
     }
 
@@ -94,7 +113,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,39 +123,56 @@ 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> {
+    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) {
-            let (def_id, _) = anon_reg;
+            let def_id = anon_reg.def_id;
             if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
                 let ret_ty = self.tcx.type_of(def_id);
                 if let ty::TyFnDef(_, _) = ret_ty.sty {
-                    if let hir_map::NodeItem(it) = self.tcx.hir.get(node_id) {
-                        if let hir::ItemFn(ref fndecl, _, _, _, _, _) = it.node {
-                            return fndecl
-                                       .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
-                                }
-                            })
-                                       .next();
-                        }
-                    }
+                    let inputs: &[_] =
+                        match self.tcx.hir.get(node_id) {
+                            hir_map::NodeItem(&hir::Item {
+                                                  node: hir::ItemFn(ref fndecl, ..), ..
+                                              }) => &fndecl.inputs,
+                            hir_map::NodeTraitItem(&hir::TraitItem {
+                                                   node: hir::TraitItemKind::Method(ref fndecl, ..),
+                                                   ..
+                                               }) => &fndecl.decl.inputs,
+                            hir_map::NodeImplItem(&hir::ImplItem {
+                                                  node: hir::ImplItemKind::Method(ref fndecl, ..),
+                                                  ..
+                                              }) => &fndecl.decl.inputs,
+
+                            _ => &[],
+                        };
+
+                    return inputs
+                               .iter()
+                               .filter_map(|arg| {
+                                               self.find_component_for_bound_region(&**arg, br)
+                                           })
+                               .next();
                 }
             }
         }
         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 +211,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 +226,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 +247,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/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 8281d4716c4..edf9ca89b33 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -75,8 +75,10 @@ use errors::{DiagnosticBuilder, DiagnosticStyledString};
 mod note;
 
 mod need_type_info;
-mod util;
+
 mod named_anon_conflict;
+#[macro_use]
+mod util;
 mod anon_anon_conflict;
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
diff --git a/src/librustc/infer/error_reporting/named_anon_conflict.rs b/src/librustc/infer/error_reporting/named_anon_conflict.rs
index 491079a1f92..0aae008396a 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;
 
@@ -30,8 +29,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         // where the anonymous region appears (there must always be one; we
         // 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, _)) =
+        // with the named one.//scope_def_id
+        let (named, anon_arg_info, region_info) =
             if sub.is_named_region() && self.is_suitable_anonymous_region(sup).is_some() {
                 (sub,
                  self.find_arg_with_anonymous_region(sup, sub).unwrap(),
@@ -44,50 +43,38 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 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;
-                }
-            }
-            _ => {}
-        }
-
-        // 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) {
+        let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = (anon_arg_info.arg,
+                                                                       anon_arg_info.arg_ty,
+                                                                       anon_arg_info.bound_region,
+                                                                       anon_arg_info.is_first,
+                                                                       region_info.def_id,
+                                                                       region_info.is_impl_item);
+        if is_impl_item {
             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))
+        if self.is_return_type_anon(scope_def_id, br) || self.is_self_anon(is_first, scope_def_id) {
+            return false;
         } 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 c8f78367420..04153038da8 100644
--- a/src/librustc/infer/error_reporting/util.rs
+++ b/src/librustc/infer/error_reporting/util.rs
@@ -16,6 +16,40 @@ use ty::{self, Region};
 use hir::def_id::DefId;
 use hir::map as hir_map;
 
+macro_rules! or_false {
+     ($v:expr) => {
+          match $v {
+               Some(v) => v,
+               None => return false,
+          }
+     }
+}
+
+// The struct contains the information about the anonymous region
+// we are searching for.
+pub struct AnonymousArgInfo<'tcx> {
+    // the argument corresponding to the anonymous region
+    pub arg: &'tcx hir::Arg,
+    // the type corresponding to the anonymopus region argument
+    pub arg_ty: ty::Ty<'tcx>,
+    // the ty::BoundRegion corresponding to the anonymous region
+    pub bound_region: ty::BoundRegion,
+    // corresponds to id the argument is the first parameter
+    // in the declaration
+    pub is_first: bool,
+}
+
+// This struct contains information regarding the
+// Refree((FreeRegion) corresponding to lifetime conflict
+pub struct FreeRegionInfo {
+    // def id corresponding to FreeRegion
+    pub def_id: DefId,
+    // the bound region corresponding to FreeRegion
+    pub boundregion: ty::BoundRegion,
+    // checks if bound region is in Impl Item
+    pub is_impl_item: bool,
+}
+
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     // This method walks the Type of the function body arguments using
     // `fold_regions()` function and returns the
@@ -28,14 +62,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     // i32, which is the type of y but with the anonymous region replaced
     // with 'a, the corresponding bound region and is_first which is true if
     // the hir::Arg is the first argument in the function declaration.
-    pub fn find_arg_with_anonymous_region
-        (&self,
-         anon_region: Region<'tcx>,
-         replace_region: Region<'tcx>)
-         -> Option<(&hir::Arg, ty::Ty<'tcx>, ty::BoundRegion, bool)> {
+    pub fn find_arg_with_anonymous_region(&self,
+                                          anon_region: Region<'tcx>,
+                                          replace_region: Region<'tcx>)
+                                          -> Option<AnonymousArgInfo> {
 
         if let ty::ReFree(ref free_region) = *anon_region {
-
             let id = free_region.scope;
             let hir = &self.tcx.hir;
             if let Some(node_id) = hir.as_local_node_id(id) {
@@ -57,7 +89,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                     });
                                 if found_anon_region {
                                     let is_first = index == 0;
-                                    Some((arg, new_arg_ty, free_region.bound_region, is_first))
+                                    Some(AnonymousArgInfo {
+                                             arg: arg,
+                                             arg_ty: new_arg_ty,
+                                             bound_region: free_region.bound_region,
+                                             is_first: is_first,
+                                         })
                                 } else {
                                     None
                                 }
@@ -79,42 +116,81 @@ 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.
-    pub fn is_suitable_anonymous_region(&self,
-                                        region: Region<'tcx>)
-                                        -> Option<(DefId, ty::BoundRegion)> {
+    pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
         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(..)) => {
-                            let container_id = self.tcx
-                                .associated_item(anonymous_region_binding_scope)
-                                .container
-                                .id();
-                            if self.tcx.impl_trait_ref(container_id).is_some() {
-                                // For now, we do not try to target impls of traits. This is
-                                // because this message is going to suggest that the user
-                                // change the fn signature, but they may not be free to do so,
-                                // since the signature must match the trait.
-                                //
-                                // FIXME(#42706) -- in some cases, we could do better here.
-                                return None;
-                            }
-                        }
-                        _ => return None, // inapplicable
-                        // we target only top-level functions
+            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();
+                let mut is_impl_item = false;
+                match self.tcx.hir.find(node_id) {
+
+                    Some(hir_map::NodeItem(..)) |
+                    Some(hir_map::NodeTraitItem(..)) => {
+                        // Success -- proceed to return Some below
                     }
-                    return Some((anonymous_region_binding_scope, free_region.bound_region));
+                    Some(hir_map::NodeImplItem(..)) => {
+                        is_impl_item =
+                            self.is_bound_region_in_impl_item(anonymous_region_binding_scope);
+                    }
+                    _ => return None,
                 }
+                return Some(FreeRegionInfo {
+                                def_id: anonymous_region_binding_scope,
+                                boundregion: free_region.bound_region,
+                                is_impl_item: is_impl_item,
+                            });
             }
-            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 {
+        is_first &&
+        self.tcx
+            .opt_associated_item(scope_def_id)
+            .map(|i| i.method_has_self_argument) == Some(true)
+    }
+
+    // Here we check if the bound region is in Impl Item.
+    pub fn is_bound_region_in_impl_item(&self, anonymous_region_binding_scope: DefId) -> bool {
+        let container_id = self.tcx
+            .associated_item(anonymous_region_binding_scope)
+            .container
+            .id();
+        if self.tcx.impl_trait_ref(container_id).is_some() {
+            // For now, we do not try to target impls of traits. This is
+            // because this message is going to suggest that the user
+            // change the fn signature, but they may not be free to do so,
+            // since the signature must match the trait.
+            //
+            // FIXME(#42706) -- in some cases, we could do better here.
+            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..1b5ac7c7b57
--- /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) {
+   |               ---
+   |               |
+   |               this type was declared with multiple 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..4933dbb7e7a
--- /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) {
+    y.b = x;
+}
+
+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..d54b526aef9
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr
@@ -0,0 +1,10 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ex3-both-anon-regions-one-is-struct-3.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