about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-05-03 18:43:28 -0400
committerNiko Matsakis <niko@alum.mit.edu>2018-05-04 05:54:01 -0400
commitaef29a058370f2941bed3fec600a95343554c436 (patch)
treebec54f7b3523125a1e01c14205b38beffd937394
parentb406d0b268977a09bd9faf5266582e97c9a01f88 (diff)
downloadrust-aef29a058370f2941bed3fec600a95343554c436.tar.gz
rust-aef29a058370f2941bed3fec600a95343554c436.zip
fix single-use lint
-rw-r--r--src/librustc/middle/resolve_lifetime.rs181
-rw-r--r--src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr14
-rw-r--r--src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr20
-rw-r--r--src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr20
-rw-r--r--src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr14
-rw-r--r--src/test/ui/in-band-lifetimes/single_use_lifetimes.rs16
-rw-r--r--src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr14
-rw-r--r--src/test/ui/single-use-lifetime/fn-types.rs26
-rw-r--r--src/test/ui/single-use-lifetime/fn-types.stderr21
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs24
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr20
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs (renamed from src/test/ui/in-band-lifetimes/single_use_lifetimes-2.rs)13
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr14
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-fn-return.rs30
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.rs29
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr14
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.rs26
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr20
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.rs28
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr14
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-struct.rs31
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.rs30
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr14
-rw-r--r--src/test/ui/single-use-lifetime/two-uses-in-fn-argument-and-return.rs (renamed from src/test/ui/in-band-lifetimes/single_use_lifetimes-5.rs)16
-rw-r--r--src/test/ui/single-use-lifetime/two-uses-in-fn-arguments.rs (renamed from src/test/ui/in-band-lifetimes/single_use_lifetimes-4.rs)18
-rw-r--r--src/test/ui/single-use-lifetime/two-uses-in-inherent-impl-header.rs (renamed from src/test/ui/in-band-lifetimes/single_use_lifetimes-3.rs)20
-rw-r--r--src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.rs28
-rw-r--r--src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr14
-rw-r--r--src/test/ui/single-use-lifetime/two-uses-in-trait-impl.rs32
29 files changed, 612 insertions, 149 deletions
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index ac4af184038..eaabc333e5d 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -257,7 +257,7 @@ struct LifetimeContext<'a, 'tcx: 'a> {
     /// Cache for cross-crate per-definition object lifetime defaults.
     xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
 
-    lifetime_uses: DefIdMap<LifetimeUseSet<'tcx>>,
+    lifetime_uses: &'a mut DefIdMap<LifetimeUseSet<'tcx>>,
 }
 
 #[derive(Debug)]
@@ -273,6 +273,11 @@ enum Scope<'a> {
         /// we should use for an early-bound region?
         next_early_index: u32,
 
+        /// Flag is set to true if, in this binder, `'_` would be
+        /// equivalent to a "single-use region". This is true on
+        /// impls, but not other kinds of items.
+        track_lifetime_uses: bool,
+
         /// Whether or not this binder would serve as the parent
         /// binder for abstract types introduced within. For example:
         ///
@@ -433,7 +438,7 @@ fn krate<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> NamedRegionMap {
             is_in_fn_syntax: false,
             labels_in_fn: vec![],
             xcrate_object_lifetime_defaults: DefIdMap(),
-            lifetime_uses: DefIdMap(),
+            lifetime_uses: &mut DefIdMap(),
         };
         for (_, item) in &krate.items {
             visitor.visit_item(item);
@@ -498,6 +503,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             | hir::ItemTrait(_, _, ref generics, ..)
             | hir::ItemTraitAlias(ref generics, ..)
             | hir::ItemImpl(_, _, _, ref generics, ..) => {
+                // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
+                // This is not true for other kinds of items.x
+                let track_lifetime_uses = match item.node {
+                    hir::ItemImpl(..) => true,
+                    _ => false,
+                };
                 // These kinds of items have only early bound lifetime parameters.
                 let mut index = if let hir::ItemTrait(..) = item.node {
                     1 // Self comes before lifetimes
@@ -513,6 +524,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     lifetimes,
                     next_early_index,
                     abstract_type_parent: true,
+                    track_lifetime_uses,
                     s: ROOT_SCOPE,
                 };
                 self.with(scope, |old_scope, this| {
@@ -540,7 +552,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        debug!("visit_ty: ty={:?}", ty);
+        debug!("visit_ty: id={:?} ty={:?}", ty.id, ty);
         match ty.node {
             hir::TyBareFn(ref c) => {
                 let next_early_index = self.next_early_index();
@@ -553,6 +565,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         .collect(),
                     s: self.scope,
                     next_early_index,
+                    track_lifetime_uses: true,
                     abstract_type_parent: false,
                 };
                 self.with(scope, |old_scope, this| {
@@ -674,6 +687,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                             lifetimes,
                             next_early_index,
                             s: this.scope,
+                            track_lifetime_uses: true,
                             abstract_type_parent: false,
                         };
                         this.with(scope, |_old_scope, this| {
@@ -688,6 +702,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         lifetimes,
                         next_early_index,
                         s: self.scope,
+                        track_lifetime_uses: true,
                         abstract_type_parent: false,
                     };
                     self.with(scope, |_old_scope, this| {
@@ -728,6 +743,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     lifetimes,
                     next_early_index,
                     s: self.scope,
+                    track_lifetime_uses: true,
                     abstract_type_parent: true,
                 };
                 self.with(scope, |_old_scope, this| {
@@ -774,6 +790,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     lifetimes,
                     next_early_index,
                     s: self.scope,
+                    track_lifetime_uses: true,
                     abstract_type_parent: true,
                 };
                 self.with(scope, |_old_scope, this| {
@@ -847,6 +864,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                                 .collect(),
                             s: self.scope,
                             next_early_index,
+                            track_lifetime_uses: true,
                             abstract_type_parent: false,
                         };
                         let result = self.with(scope, |old_scope, this| {
@@ -913,6 +931,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     .collect(),
                 s: self.scope,
                 next_early_index,
+                track_lifetime_uses: true,
                 abstract_type_parent: false,
             };
             self.with(scope, |old_scope, this| {
@@ -1104,10 +1123,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) {
                 }
 
                 Scope::Binder {
-                    ref lifetimes,
-                    s,
-                    next_early_index: _,
-                    abstract_type_parent: _,
+                    ref lifetimes, s, ..
                 } => {
                     // FIXME (#24278): non-hygienic comparison
                     if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) {
@@ -1255,33 +1271,70 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         F: for<'b> FnOnce(ScopeRef, &mut LifetimeContext<'b, 'tcx>),
     {
         let LifetimeContext {
-            tcx, ref mut map, ..
-        } = *self;
+            tcx,
+            map,
+            lifetime_uses,
+            ..
+        } = self;
         let labels_in_fn = replace(&mut self.labels_in_fn, vec![]);
         let xcrate_object_lifetime_defaults =
             replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap());
         let mut this = LifetimeContext {
-            tcx,
-            map: *map,
+            tcx: *tcx,
+            map: map,
             scope: &wrap_scope,
             trait_ref_hack: self.trait_ref_hack,
             is_in_fn_syntax: self.is_in_fn_syntax,
             labels_in_fn,
             xcrate_object_lifetime_defaults,
-            lifetime_uses: DefIdMap(),
+            lifetime_uses: lifetime_uses,
         };
         debug!("entering scope {:?}", this.scope);
         f(self.scope, &mut this);
+        this.check_uses_for_lifetimes_defined_by_scope();
         debug!("exiting scope {:?}", this.scope);
         self.labels_in_fn = this.labels_in_fn;
         self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
+    }
+
+    fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
+        let defined_by = match self.scope {
+            Scope::Binder { lifetimes, .. } => lifetimes,
+            _ => {
+                debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope");
+                return;
+            }
+        };
 
-        for (def_id, lifetimeuseset) in &this.lifetime_uses {
+        for region in defined_by.values() {
+            debug!(
+                "check_uses_for_lifetimes_defined_by_scope: region = {:?}",
+                region
+            );
+
+            let def_id = match region {
+                Region::EarlyBound(_, def_id, _)
+                | Region::LateBound(_, def_id, _)
+                | Region::Free(_, def_id) => def_id,
+
+                Region::LateBoundAnon(..) | Region::Static => continue,
+            };
+
+            debug!(
+                "check_uses_for_lifetimes_defined_by_scope: def_id = {:?}",
+                def_id
+            );
+
+            let lifetimeuseset = self.lifetime_uses.remove(def_id);
+            debug!(
+                "check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}",
+                lifetimeuseset
+            );
             match lifetimeuseset {
-                &LifetimeUseSet::One(_) => {
-                    let node_id = this.tcx.hir.as_local_node_id(*def_id).unwrap();
+                Some(LifetimeUseSet::One(_)) => {
+                    let node_id = self.tcx.hir.as_local_node_id(*def_id).unwrap();
                     debug!("node id first={:?}", node_id);
-                    if let hir::map::NodeLifetime(hir_lifetime) = this.tcx.hir.get(node_id) {
+                    if let hir::map::NodeLifetime(hir_lifetime) = self.tcx.hir.get(node_id) {
                         let span = hir_lifetime.span;
                         let id = hir_lifetime.id;
                         debug!(
@@ -1289,22 +1342,23 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                             node_id, span, hir_lifetime
                         );
 
-                        this.tcx
+                        self.tcx
                             .struct_span_lint_node(
                                 lint::builtin::SINGLE_USE_LIFETIME,
                                 id,
                                 span,
                                 &format!(
-                                    "lifetime name `{}` only used once",
+                                    "lifetime parameter `{}` only used once",
                                     hir_lifetime.name.name()
                                 ),
                             )
                             .emit();
                     }
                 }
-                _ => {
+                Some(LifetimeUseSet::Many) => {
                     debug!("Not one use lifetime");
                 }
+                None => {}
             }
         }
     }
@@ -1372,6 +1426,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             next_early_index,
             s: self.scope,
             abstract_type_parent: true,
+            track_lifetime_uses: false,
         };
         self.with(scope, move |old_scope, this| {
             this.check_lifetime_params(old_scope, &generics.params);
@@ -1437,10 +1492,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 }
 
                 Scope::Binder {
-                    ref lifetimes,
-                    s,
-                    next_early_index: _,
-                    abstract_type_parent: _,
+                    ref lifetimes, s, ..
                 } => {
                     if let Some(&def) = lifetimes.get(&lifetime_ref.name) {
                         break Some(def.shifted(late_depth));
@@ -1631,6 +1683,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         inputs: &'tcx [P<hir::Ty>],
         output: Option<&'tcx P<hir::Ty>>,
     ) {
+        debug!("visit_fn_like_elision: enter");
         let mut arg_elide = Elide::FreshLateAnon(Cell::new(0));
         let arg_scope = Scope::Elision {
             elide: arg_elide.clone(),
@@ -1653,6 +1706,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             None => return,
         };
 
+        debug!("visit_fn_like_elision: determine output");
+
         // Figure out if there's a body we can get argument names from,
         // and whether there's a `self` argument (treated specially).
         let mut assoc_item_kind = None;
@@ -1812,11 +1867,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             Elide::Error(arg_lifetimes)
         };
 
+        debug!("visit_fn_like_elision: elide={:?}", elide);
+
         let scope = Scope::Elision {
             elide,
             s: self.scope,
         };
         self.with(scope, |_, this| this.visit_ty(output));
+        debug!("visit_fn_like_elision: exit");
 
         struct GatherLifetimes<'a> {
             map: &'a NamedRegionMap,
@@ -2182,10 +2240,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 }
 
                 Scope::Binder {
-                    ref lifetimes,
-                    s,
-                    next_early_index: _,
-                    abstract_type_parent: _,
+                    ref lifetimes, s, ..
                 } => {
                     if let Some(&def) = lifetimes.get(&lifetime.name) {
                         let node_id = self.tcx.hir.as_local_node_id(def.id().unwrap()).unwrap();
@@ -2205,6 +2260,50 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         }
     }
 
+    /// Returns true if, in the current scope, replacing `'_` would be
+    /// equivalent to a single-use lifetime.
+    fn track_lifetime_uses(&self) -> bool {
+        let mut scope = self.scope;
+        loop {
+            match *scope {
+                Scope::Root => break false,
+
+                // Inside of items, it depends on the kind of item.
+                Scope::Binder {
+                    track_lifetime_uses,
+                    ..
+                } => break track_lifetime_uses,
+
+                // Inside a body, `'_` will use an inference variable,
+                // should be fine.
+                Scope::Body { .. } => break true,
+
+                // A lifetime only used in a fn argument could as well
+                // be replaced with `'_`, as that would generate a
+                // fresh name, too.
+                Scope::Elision {
+                    elide: Elide::FreshLateAnon(_),
+                    ..
+                } => break true,
+
+                // In the return type or other such place, `'_` is not
+                // going to make a fresh name, so we cannot
+                // necessarily replace a single-use lifetime with
+                // `'_`.
+                Scope::Elision {
+                    elide: Elide::Exact(_),
+                    ..
+                } => break false,
+                Scope::Elision {
+                    elide: Elide::Error(_),
+                    ..
+                } => break false,
+
+                Scope::ObjectLifetimeDefault { s, .. } => scope = s,
+            }
+        }
+    }
+
     fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
         if lifetime_ref.id == ast::DUMMY_NODE_ID {
             span_bug!(
@@ -2231,11 +2330,31 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             | Region::LateBound(_, def_id, _)
             | Region::EarlyBound(_, def_id, _) => {
                 // A lifetime declared by the user.
-                if !self.lifetime_uses.contains_key(&def_id) {
-                    self.lifetime_uses
-                        .insert(def_id, LifetimeUseSet::One(lifetime_ref));
+                let def_local_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+                if def_local_id == lifetime_ref.id {
+                    // This is weird. Because the HIR defines a
+                    // lifetime *definition* as wrapping a Lifetime,
+                    // we wind up invoking this method also for the
+                    // definitions in some cases (notably
+                    // higher-ranked types). This means that a
+                    // lifetime with one use (e.g., `for<'a> fn(&'a
+                    // u32)`) wind up being counted as two uses.  To
+                    // avoid that, we just ignore the lifetime that
+                    // corresponds to the definition.
                 } else {
-                    self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
+                    let track_lifetime_uses = self.track_lifetime_uses();
+                    debug!(
+                        "insert_lifetime: track_lifetime_uses={}",
+                        track_lifetime_uses
+                    );
+                    if track_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) {
+                        debug!("insert_lifetime: first use of {:?}", def_id);
+                        self.lifetime_uses
+                            .insert(def_id, LifetimeUseSet::One(lifetime_ref));
+                    } else {
+                        debug!("insert_lifetime: many uses of {:?}", def_id);
+                        self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
+                    }
                 }
             }
         }
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr
deleted file mode 100644
index 38d05369fb8..00000000000
--- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-2.rs:12:10
-   |
-LL | fn deref<'x>() -> &'x u32 { //~ ERROR lifetime name `'x` only used once
-   |          ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes-2.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr
deleted file mode 100644
index 49c06aafbe5..00000000000
--- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-3.rs:11:12
-   |
-LL | struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
-   |            ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes-3.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: lifetime name `'y` only used once
-  --> $DIR/single_use_lifetimes-3.rs:16:6
-   |
-LL | impl<'y> Foo<'y> { //~ ERROR lifetime name `'y` only used once
-   |      ^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr
deleted file mode 100644
index 2df370f5d02..00000000000
--- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-4.rs:12:12
-   |
-LL | struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
-   |            ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes-4.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-4.rs:16:10
-   |
-LL | enum Bar<'x> { //~ ERROR lifetime name `'x` only used once
-   |          ^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr
deleted file mode 100644
index eec426e4e63..00000000000
--- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-5.rs:12:11
-   |
-LL | trait Foo<'x> { //~ ERROR lifetime name `'x` only used once
-   |           ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes-5.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes.rs
deleted file mode 100644
index a97056b6240..00000000000
--- a/src/test/ui/in-band-lifetimes/single_use_lifetimes.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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.
-#![deny(single_use_lifetime)]
-
-fn deref<'x>(v: &'x u32) -> u32 { //~ ERROR lifetime name `'x` only used once
-    *v
-}
-
-fn main() {}
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr
deleted file mode 100644
index 15917d3c085..00000000000
--- a/src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes.rs:12:10
-   |
-LL | fn deref<'x>(v: &'x u32) -> u32 { //~ ERROR lifetime name `'x` only used once
-   |          ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/single-use-lifetime/fn-types.rs b/src/test/ui/single-use-lifetime/fn-types.rs
new file mode 100644
index 00000000000..c5d98d26048
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/fn-types.rs
@@ -0,0 +1,26 @@
+// Copyright 2016 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.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument.
+
+struct Foo {
+  a: for<'a> fn(&'a u32), //~ ERROR `'a` only used once
+  b: for<'a> fn(&'a u32, &'a u32), // OK, used twice.
+  c: for<'a> fn(&'a u32) -> &'a u32, // OK, used twice.
+  d: for<'a> fn() -> &'a u32, // OK, used only in return type.
+    //~^ ERROR return type references lifetime `'a`, which is not constrained by the fn input types
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/fn-types.stderr b/src/test/ui/single-use-lifetime/fn-types.stderr
new file mode 100644
index 00000000000..bec712b004c
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/fn-types.stderr
@@ -0,0 +1,21 @@
+error: lifetime parameter `'a` only used once
+  --> $DIR/fn-types.rs:19:10
+   |
+LL |   a: for<'a> fn(&'a u32), //~ ERROR `'a` only used once
+   |          ^^
+   |
+note: lint level defined here
+  --> $DIR/fn-types.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
+  --> $DIR/fn-types.rs:22:22
+   |
+LL |   d: for<'a> fn() -> &'a u32, // OK, used only in return type.
+   |                      ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0581`.
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs
new file mode 100644
index 00000000000..9001a8de29a
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs
@@ -0,0 +1,24 @@
+// Copyright 2016 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.
+
+#![feature(in_band_lifetimes)]
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument, even with in band lifetimes.
+
+fn a(x: &'a u32, y: &'b u32) {
+    //~^ ERROR `'a` only used once
+    //~| ERROR `'b` only used once
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr
new file mode 100644
index 00000000000..2011359a511
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr
@@ -0,0 +1,20 @@
+error: lifetime parameter `'b` only used once
+  --> $DIR/one-use-in-fn-argument-in-band.rs:19:22
+   |
+LL | fn a(x: &'a u32, y: &'b u32) {
+   |                      ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-fn-argument-in-band.rs:12:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: lifetime parameter `'a` only used once
+  --> $DIR/one-use-in-fn-argument-in-band.rs:19:10
+   |
+LL | fn a(x: &'a u32, y: &'b u32) {
+   |          ^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.rs b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs
index 005f1f033b6..2a9e80d56c3 100644
--- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.rs
+++ b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs
@@ -1,4 +1,4 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -7,10 +7,15 @@
 // <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.
+
 #![deny(single_use_lifetime)]
-// FIXME(#44752) -- this scenario should not be warned
-fn deref<'x>() -> &'x u32 { //~ ERROR lifetime name `'x` only used once
-    22
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument.
+
+fn a<'a>(x: &'a u32) { //~ ERROR `'a` only used once
 }
 
 fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr
new file mode 100644
index 00000000000..e9a3570b3fb
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr
@@ -0,0 +1,14 @@
+error: lifetime parameter `'a` only used once
+  --> $DIR/one-use-in-fn-argument.rs:18:6
+   |
+LL | fn a<'a>(x: &'a u32) { //~ ERROR `'a` only used once
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-fn-argument.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs b/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs
new file mode 100644
index 00000000000..d024094ae71
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs
@@ -0,0 +1,30 @@
+// Copyright 2016 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.
+
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO NOT warn when lifetime name is used only
+// once in a fn return type -- using `'_` is not legal there,
+// as it must refer back to an argument.
+//
+// (Normally, using `'static` would be preferred, but there are
+// times when that is not what you want.)
+//
+// run-pass
+
+fn b<'a>() -> &'a u32 { // OK: used only in return type
+    &22
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.rs b/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.rs
new file mode 100644
index 00000000000..9cdad09e33d
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.rs
@@ -0,0 +1,29 @@
+// Copyright 2016 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.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn for a lifetime used only once in an impl.
+//
+// (Actually, until #15872 is fixed, you can't use `'_` here, but
+// hopefully that will come soon.)
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+    fn inherent_a(&self) {
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr b/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr
new file mode 100644
index 00000000000..1718f193188
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr
@@ -0,0 +1,14 @@
+error: lifetime parameter `'f` only used once
+  --> $DIR/one-use-in-inherent-impl-header.rs:24:6
+   |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-inherent-impl-header.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.rs b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.rs
new file mode 100644
index 00000000000..1ca078cdb3b
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.rs
@@ -0,0 +1,26 @@
+// Copyright 2016 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.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn for a lifetime used only once in an inherent method.
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+    fn inherent_a<'a>(&self, data: &'a u32) { //~ ERROR `'a` only used once
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr
new file mode 100644
index 00000000000..38e90e76f56
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr
@@ -0,0 +1,20 @@
+error: lifetime parameter `'a` only used once
+  --> $DIR/one-use-in-inherent-method-argument.rs:22:19
+   |
+LL |     fn inherent_a<'a>(&self, data: &'a u32) { //~ ERROR `'a` only used once
+   |                   ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-inherent-method-argument.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: lifetime parameter `'f` only used once
+  --> $DIR/one-use-in-inherent-method-argument.rs:21:6
+   |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+   |      ^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.rs b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.rs
new file mode 100644
index 00000000000..7d2ffa379ad
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.rs
@@ -0,0 +1,28 @@
+// Copyright 2016 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.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO NOT warn for a lifetime used just once in a return type,
+// where that return type is in an inherent method.
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+    fn inherent_a<'a>(&self) -> &'a u32 { // OK for 'a
+        &22
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr
new file mode 100644
index 00000000000..32fd284949e
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr
@@ -0,0 +1,14 @@
+error: lifetime parameter `'f` only used once
+  --> $DIR/one-use-in-inherent-method-return.rs:22:6
+   |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-inherent-method-return.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-struct.rs b/src/test/ui/single-use-lifetime/one-use-in-struct.rs
new file mode 100644
index 00000000000..5c758d9db07
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/one-use-in-struct.rs
@@ -0,0 +1,31 @@
+// Copyright 2016 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.
+
+// Test that we do not warn for named lifetimes in structs,
+// even when they are only used once (since to not use a named
+// lifetime is illegal!)
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+enum Bar<'f> {
+    Data(&'f u32)
+}
+
+trait Baz<'f> { }
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.rs b/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.rs
new file mode 100644
index 00000000000..99e9eaf98ad
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.rs
@@ -0,0 +1,30 @@
+// Copyright 2016 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.
+
+// Test that we DO warn for a lifetime on an impl used only in `&self`
+// in a trait method.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Iterator for Foo<'f> {
+    type Item = &'f u32;
+
+    fn next<'g>(&'g mut self) -> Option<Self::Item> { //~ ERROR `'g` only used once
+        None
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr b/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr
new file mode 100644
index 00000000000..e5278671a1a
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr
@@ -0,0 +1,14 @@
+error: lifetime parameter `'g` only used once
+  --> $DIR/one-use-in-trait-method-argument.rs:25:13
+   |
+LL |     fn next<'g>(&'g mut self) -> Option<Self::Item> { //~ ERROR `'g` only used once
+   |             ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-trait-method-argument.rs:14:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.rs b/src/test/ui/single-use-lifetime/two-uses-in-fn-argument-and-return.rs
index cef904c4896..d210be4ba2a 100644
--- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.rs
+++ b/src/test/ui/single-use-lifetime/two-uses-in-fn-argument-and-return.rs
@@ -1,4 +1,4 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -7,10 +7,18 @@
 // <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.
+
+// Test that we DO NOT warn when lifetime name is used in
+// both the argument and return.
+//
+// compile-pass
+
 #![deny(single_use_lifetime)]
-// Should not issue a warning, as explicit lifetimes are mandatory in this case:
-trait Foo<'x> { //~ ERROR lifetime name `'x` only used once
-    fn foo(&self, arg: &'x u32);
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn c<'a>(x: &'a u32) -> &'a u32 { // OK: used twice
+    &22
 }
 
 fn main() { }
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.rs b/src/test/ui/single-use-lifetime/two-uses-in-fn-arguments.rs
index 4ac8f8c0d4e..f43a3e116ef 100644
--- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.rs
+++ b/src/test/ui/single-use-lifetime/two-uses-in-fn-arguments.rs
@@ -1,4 +1,4 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -7,14 +7,20 @@
 // <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.
+
+// Test that we DO NOT warn when lifetime name is used multiple
+// argments, or more than once in a single argument.
+//
+// compile-pass
+
 #![deny(single_use_lifetime)]
- // Neither should issue a warning, as explicit lifetimes are mandatory in this case
-struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
-    x: &'x u32
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn c<'a>(x: &'a u32, y: &'a u32) { // OK: used twice
 }
 
-enum Bar<'x> { //~ ERROR lifetime name `'x` only used once
-    Variant(&'x u32)
+fn d<'a>(x: (&'a u32, &'a u32)) { // OK: used twice
 }
 
 fn main() { }
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.rs b/src/test/ui/single-use-lifetime/two-uses-in-inherent-impl-header.rs
index 263548ca7f4..d224d9fefa1 100644
--- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.rs
+++ b/src/test/ui/single-use-lifetime/two-uses-in-inherent-impl-header.rs
@@ -1,4 +1,4 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -7,14 +7,22 @@
 // <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.
+
+// Test that we DO NOT warn for a lifetime used twice in an impl.
+//
+// compile-pass
+
 #![deny(single_use_lifetime)]
-struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
-    x: &'x u32 // no warning!
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
 }
 
-// Once #44524 is fixed, this should issue a warning.
-impl<'y> Foo<'y> { //~ ERROR lifetime name `'y` only used once
-    fn method() { }
+impl<'f> Foo<'f> {
+    fn inherent_a(&self, data: &'f u32) {
+    }
 }
 
 fn main() { }
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.rs b/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.rs
new file mode 100644
index 00000000000..7b69a6f0d52
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.rs
@@ -0,0 +1,28 @@
+// Copyright 2016 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.
+
+// Test that we DO NOT warn for a lifetime used twice in an impl method and
+// header.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+    fn inherent_a<'a>(&self, data: &'a u32) -> &'a u32{
+      data
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr b/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr
new file mode 100644
index 00000000000..6fc66611b1d
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr
@@ -0,0 +1,14 @@
+error: lifetime parameter `'f` only used once
+  --> $DIR/two-uses-in-inherent-method-argument-and-return.rs:22:6
+   |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/two-uses-in-inherent-method-argument-and-return.rs:14:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-trait-impl.rs b/src/test/ui/single-use-lifetime/two-uses-in-trait-impl.rs
new file mode 100644
index 00000000000..ffba3d8527d
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/two-uses-in-trait-impl.rs
@@ -0,0 +1,32 @@
+// Copyright 2016 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.
+
+// Test that we DO NOT warn for a lifetime on an impl used in both
+// header and in an associated type.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Iterator for Foo<'f> {
+    type Item = &'f u32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        None
+    }
+}
+
+fn main() { }