diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2018-05-03 18:43:28 -0400 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2018-05-04 05:54:01 -0400 |
| commit | aef29a058370f2941bed3fec600a95343554c436 (patch) | |
| tree | bec54f7b3523125a1e01c14205b38beffd937394 | |
| parent | b406d0b268977a09bd9faf5266582e97c9a01f88 (diff) | |
| download | rust-aef29a058370f2941bed3fec600a95343554c436.tar.gz rust-aef29a058370f2941bed3fec600a95343554c436.zip | |
fix single-use lint
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() { } |
