Skip to content

Commit 6a590e0

Browse files
committed
Bail on lifetime-y trait bounds in elision lint (fixes #292)
1 parent 5b7ec55 commit 6a590e0

File tree

2 files changed

+42
-26
lines changed

2 files changed

+42
-26
lines changed

src/lifetimes.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use syntax::ast::*;
22
use rustc::lint::*;
33
use syntax::codemap::Span;
4-
use syntax::visit::{Visitor, walk_ty, walk_ty_param_bound};
4+
use syntax::visit::{Visitor, walk_ty, walk_ty_param_bound, walk_ty_param_bounds_helper};
55
use std::collections::HashSet;
66

77
use utils::{in_external_macro, span_lint};
@@ -53,22 +53,25 @@ fn check_fn_inner(cx: &Context, decl: &FnDecl, slf: Option<&ExplicitSelf>,
5353
if in_external_macro(cx, span) || has_where_lifetimes(&generics.where_clause) {
5454
return;
5555
}
56-
if could_use_elision(decl, slf, &generics.lifetimes) {
56+
if could_use_elision(decl, slf, generics) {
5757
span_lint(cx, NEEDLESS_LIFETIMES, span,
5858
"explicit lifetimes given in parameter types where they could be elided");
5959
}
6060
}
6161

6262
fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>,
63-
named_lts: &[LifetimeDef]) -> bool {
63+
generics: &Generics) -> bool {
6464
// There are two scenarios where elision works:
6565
// * no output references, all input references have different LT
6666
// * output references, exactly one input reference with same LT
6767
// All lifetimes must be unnamed, 'static or defined without bounds on the
6868
// level of the current item.
6969

7070
// check named LTs
71-
let allowed_lts = allowed_lts_from(named_lts);
71+
let Generics {ref lifetimes, ref ty_params, ..} = *generics;
72+
let allowed_lts = allowed_lts_from(lifetimes);
73+
74+
if params_contain_lts(ty_params) {return false;}
7275

7376
// these will collect all the lifetimes for references in arg/return types
7477
let mut input_visitor = RefVisitor(Vec::new());
@@ -147,6 +150,14 @@ fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> {
147150
allowed_lts
148151
}
149152

153+
fn params_contain_lts(params: &[TyParam]) -> bool {
154+
let mut param_vis = RefVisitor(Vec::new());
155+
for param in params {
156+
walk_ty_param_bounds_helper(&mut param_vis, &param.bounds);
157+
}
158+
!param_vis.0.is_empty()
159+
}
160+
150161
/// Number of unique lifetimes in the given vector.
151162
fn unique_lifetimes(lts: &[RefLt]) -> usize {
152163
lts.iter().collect::<HashSet<_>>().len()
@@ -183,9 +194,6 @@ impl<'v> Visitor<'v> for RefVisitor {
183194
fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) {
184195
self.record(&Some(*lifetime));
185196
}
186-
187-
// for lifetime bounds; the default impl calls visit_lifetime_ref
188-
fn visit_lifetime_bound(&mut self, _: &'v Lifetime) { }
189197
}
190198

191199
/// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to

tests/compile-fail/lifetimes.rs

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,49 @@
33

44
#![deny(needless_lifetimes)]
55
#![allow(dead_code)]
6-
fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { }
6+
#![allow(unused)]
7+
fn distinct_lifetimes<'a, 'b>(x: &'a u8, y: &'b u8, z: u8) { }
78
//~^ERROR explicit lifetimes given
89

9-
fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) { }
10+
fn distinct_and_static<'a, 'b>(x: &'a u8, y: &'b u8, z: &'static u8) { }
1011
//~^ERROR explicit lifetimes given
1112

12-
fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) { } // no error, same lifetime on two params
13+
fn same_lifetime_on_input<'a>(x: &'a u8, y: &'a u8) { } // no error, same lifetime on two params
1314

14-
fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) { } // no error, static involved
15+
fn only_static_on_input(x: &u8, y: &u8, z: &'static u8) { } // no error, static involved
1516

16-
fn mut_and_static_input(_x: &mut u8, _y: &'static str) { }
17+
fn mut_and_static_input(x: &mut u8, y: &'static str) { }
1718

18-
fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { x }
19+
fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { x }
1920
//~^ERROR explicit lifetimes given
2021

21-
fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 { x } // no error, multiple input refs
22+
fn multiple_in_and_out_1<'a>(x: &'a u8, y: &'a u8) -> &'a u8 { x } // no error, multiple input refs
2223

23-
fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { x } // no error, multiple input refs
24+
fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, y: &'b u8) -> &'a u8 { x } // no error, multiple input refs
2425

25-
fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 { x } // no error, static involved
26+
fn in_static_and_out<'a>(x: &'a u8, y: &'static u8) -> &'a u8 { x } // no error, static involved
2627

27-
fn deep_reference_1<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> { Ok(x) } // no error
28+
fn deep_reference_1<'a, 'b>(x: &'a u8, y: &'b u8) -> Result<&'a u8, ()> { Ok(x) } // no error
2829

2930
fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 { x.unwrap() } // no error, two input refs
3031

31-
fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { Ok(x) }
32+
fn deep_reference_3<'a>(x: &'a u8, y: u8) -> Result<&'a u8, ()> { Ok(x) }
3233
//~^ERROR explicit lifetimes given
3334

3435
// where clause, but without lifetimes
35-
fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> where T: Copy { Ok(x) }
36+
fn where_clause_without_lt<'a, T>(x: &'a u8, y: u8) -> Result<&'a u8, ()> where T: Copy { Ok(x) }
3637
//~^ERROR explicit lifetimes given
3738

3839
type Ref<'r> = &'r u8;
3940

40-
fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) { } // no error, same lifetime on two params
41+
fn lifetime_param_1<'a>(x: Ref<'a>, y: &'a u8) { } // no error, same lifetime on two params
4142

42-
fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) { }
43+
fn lifetime_param_2<'a, 'b>(x: Ref<'a>, y: &'b u8) { }
4344
//~^ERROR explicit lifetimes given
4445

45-
fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) { } // no error, bounded lifetime
46+
fn lifetime_param_3<'a, 'b: 'a>(x: Ref<'a>, y: &'b u8) { } // no error, bounded lifetime
4647

47-
fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8) where 'b: 'a { } // no error, bounded lifetime
48+
fn lifetime_param_4<'a, 'b>(x: Ref<'a>, y: &'b u8) where 'b: 'a { } // no error, bounded lifetime
4849

4950
struct Lt<'a, I: 'static> {
5051
x: &'a I
@@ -62,16 +63,23 @@ struct X {
6263
x: u8,
6364
}
6465

66+
// no errors, bounded lifetimes:
67+
trait Trait<'a> {}
68+
fn trait_bound<'a, T: Trait<'a>>(x: &'a u8, y: T) {}
69+
fn trait_bound_where<'a, T>(x: &'a u8, y: T) where T: Trait<'a> {}
70+
fn lt_bound<'a, T: 'a>(x: &'a u8, y: T) {}
71+
fn lt_bound_where<'a, T>(x: &'a u8, y: T) where T : 'a {}
72+
6573
impl X {
6674
fn self_and_out<'s>(&'s self) -> &'s u8 { &self.x }
6775
//~^ERROR explicit lifetimes given
6876

69-
fn self_and_in_out<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 { &self.x } // no error, multiple input refs
77+
fn self_and_in_out<'s, 't>(&'s self, x: &'t u8) -> &'s u8 { &self.x } // no error, multiple input refs
7078

71-
fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) { }
79+
fn distinct_self_and_in<'s, 't>(&'s self, x: &'t u8) { }
7280
//~^ERROR explicit lifetimes given
7381

74-
fn self_and_same_in<'s>(&'s self, _x: &'s u8) { } // no error, same lifetimes on two params
82+
fn self_and_same_in<'s>(&'s self, x: &'s u8) { } // no error, same lifetimes on two params
7583
}
7684

7785
struct Foo<'a>(&'a u8);

0 commit comments

Comments
 (0)