Skip to content

Commit 2f80ead

Browse files
committed
Auto merge of #138677 - shepmaster:consistent-elided-lifetime-syntax, r=traviscross,jieyouxu
Add a new `mismatched-lifetime-syntaxes` lint The lang-team [discussed this](https://hackmd.io/nf4ZUYd7Rp6rq-1svJZSaQ) and I attempted to [summarize](#120808 (comment)) their decision. The summary-of-the-summary is: - Using two different kinds of syntax for elided lifetimes is confusing. In rare cases, it may even [lead to unsound code](#48686)! Some examples: ```rust // Lint will warn about these fn(v: ContainsLifetime) -> ContainsLifetime<'_>; fn(&'static u8) -> &u8; ``` - Matching up references with no lifetime syntax, references with anonymous lifetime syntax, and paths with anonymous lifetime syntax is an exception to the simplest possible rule: ```rust // Lint will not warn about these fn(&u8) -> &'_ u8; fn(&'_ u8) -> &u8; fn(&u8) -> ContainsLifetime<'_>; ``` - Having a lint for consistent syntax of elided lifetimes will make the [future goal](#91639) of warning-by-default for paths participating in elision much simpler. --- This new lint attempts to accomplish the goal of enforcing consistent syntax. In the process, it supersedes and replaces the existing `elided-named-lifetimes` lint, which means it starts out life as warn-by-default.
2 parents 9b8bf53 + 8b59e34 commit 2f80ead

15 files changed

+54
-45
lines changed

tests/ui/explicit_iter_loop.fixed

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,11 @@ fn main() {
7777

7878
struct NoIntoIter();
7979
impl NoIntoIter {
80-
fn iter(&self) -> slice::Iter<u8> {
80+
fn iter(&self) -> slice::Iter<'_, u8> {
8181
unimplemented!()
8282
}
8383

84-
fn iter_mut(&mut self) -> slice::IterMut<u8> {
84+
fn iter_mut(&mut self) -> slice::IterMut<'_, u8> {
8585
unimplemented!()
8686
}
8787
}

tests/ui/explicit_iter_loop.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,11 @@ fn main() {
7777

7878
struct NoIntoIter();
7979
impl NoIntoIter {
80-
fn iter(&self) -> slice::Iter<u8> {
80+
fn iter(&self) -> slice::Iter<'_, u8> {
8181
unimplemented!()
8282
}
8383

84-
fn iter_mut(&mut self) -> slice::IterMut<u8> {
84+
fn iter_mut(&mut self) -> slice::IterMut<'_, u8> {
8585
unimplemented!()
8686
}
8787
}

tests/ui/iter_next_loop.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ fn main() {
88

99
struct Unrelated(&'static [u8]);
1010
impl Unrelated {
11-
fn next(&self) -> std::slice::Iter<u8> {
11+
fn next(&self) -> std::slice::Iter<'_, u8> {
1212
self.0.iter()
1313
}
1414
}

tests/ui/iter_not_returning_iterator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ impl S {
7171

7272
struct S2([u8]);
7373
impl S2 {
74-
fn iter(&self) -> core::slice::Iter<u8> {
74+
fn iter(&self) -> core::slice::Iter<'_, u8> {
7575
self.0.iter()
7676
}
7777
}

tests/ui/methods.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ struct Lt2<'a> {
4949

5050
impl<'a> Lt2<'a> {
5151
// The lifetime is different, but that’s irrelevant; see issue #734.
52-
pub fn new(s: &str) -> Lt2 {
52+
pub fn new(s: &str) -> Lt2<'_> {
5353
unimplemented!()
5454
}
5555
}

tests/ui/needless_lifetimes.fixed

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
clippy::unnecessary_wraps,
1111
dyn_drop,
1212
clippy::get_first,
13-
elided_named_lifetimes
13+
mismatched_lifetime_syntaxes,
1414
)]
1515

1616
extern crate proc_macros;

tests/ui/needless_lifetimes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
clippy::unnecessary_wraps,
1111
dyn_drop,
1212
clippy::get_first,
13-
elided_named_lifetimes
13+
mismatched_lifetime_syntaxes,
1414
)]
1515

1616
extern crate proc_macros;

tests/ui/ptr_arg.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ mod issue_9218 {
312312

313313
// Inferred to be `&'a str`, afaik.
314314
fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
315-
//~^ ERROR: elided lifetime has a name
315+
//~^ ERROR: lifetime flowing from input to output with different syntax
316316
todo!()
317317
}
318318
}

tests/ui/ptr_arg.stderr

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
1-
error: elided lifetime has a name
2-
--> tests/ui/ptr_arg.rs:314:56
3-
|
4-
LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
5-
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
6-
|
7-
= note: `-D elided-named-lifetimes` implied by `-D warnings`
8-
= help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]`
9-
101
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
112
--> tests/ui/ptr_arg.rs:13:14
123
|
@@ -240,5 +231,21 @@ error: writing `&String` instead of `&str` involves a new object where a slice w
240231
LL | fn good(v1: &String, v2: &String) {
241232
| ^^^^^^^ help: change this to: `&str`
242233

234+
error: lifetime flowing from input to output with different syntax can be confusing
235+
--> tests/ui/ptr_arg.rs:314:36
236+
|
237+
LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
238+
| ^^ ^^ ---- the lifetime gets resolved as `'a`
239+
| | |
240+
| | these lifetimes flow to the output
241+
| these lifetimes flow to the output
242+
|
243+
= note: `-D mismatched-lifetime-syntaxes` implied by `-D warnings`
244+
= help: to override `-D warnings` add `#[allow(mismatched_lifetime_syntaxes)]`
245+
help: one option is to consistently use `'a`
246+
|
247+
LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &'a str {
248+
| ++
249+
243250
error: aborting due to 27 previous errors
244251

tests/ui/significant_drop_in_scrutinee.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ struct CounterWrapper<'a> {
191191
}
192192

193193
impl<'a> CounterWrapper<'a> {
194-
fn new(counter: &Counter) -> CounterWrapper {
194+
fn new(counter: &Counter) -> CounterWrapper<'_> {
195195
counter.i.fetch_add(1, Ordering::Relaxed);
196196
CounterWrapper { counter }
197197
}
@@ -204,7 +204,7 @@ impl<'a> Drop for CounterWrapper<'a> {
204204
}
205205

206206
impl Counter {
207-
fn temp_increment(&self) -> Vec<CounterWrapper> {
207+
fn temp_increment(&self) -> Vec<CounterWrapper<'_>> {
208208
vec![CounterWrapper::new(self), CounterWrapper::new(self)]
209209
}
210210
}
@@ -480,7 +480,7 @@ impl StateWithBoxedMutexGuard {
480480
fn new() -> StateWithBoxedMutexGuard {
481481
StateWithBoxedMutexGuard { u: Mutex::new(42) }
482482
}
483-
fn lock(&self) -> Box<MutexGuard<u64>> {
483+
fn lock(&self) -> Box<MutexGuard<'_, u64>> {
484484
Box::new(self.u.lock().unwrap())
485485
}
486486
}
@@ -507,7 +507,7 @@ impl StateStringWithBoxedMutexGuard {
507507
s: Mutex::new("A String".to_owned()),
508508
}
509509
}
510-
fn lock(&self) -> Box<MutexGuard<String>> {
510+
fn lock(&self) -> Box<MutexGuard<'_, String>> {
511511
Box::new(self.s.lock().unwrap())
512512
}
513513
}
@@ -686,11 +686,11 @@ struct Guard<'a, T>(MutexGuard<'a, T>);
686686
struct Ref<'a, T>(&'a T);
687687

688688
impl<'a, T> Guard<'a, T> {
689-
fn guard(&self) -> &MutexGuard<T> {
689+
fn guard(&self) -> &MutexGuard<'_, T> {
690690
&self.0
691691
}
692692

693-
fn guard_ref(&self) -> Ref<MutexGuard<T>> {
693+
fn guard_ref(&self) -> Ref<'_, MutexGuard<'_, T>> {
694694
Ref(&self.0)
695695
}
696696

tests/ui/trivially_copy_pass_by_ref.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ fn good_return_explicit_lt_ref<'a>(foo: &'a Foo) -> &'a u32 {
4141
&foo.0
4242
}
4343

44+
#[allow(mismatched_lifetime_syntaxes)]
4445
fn good_return_implicit_lt_struct(foo: &Foo) -> FooRef {
4546
FooRef { foo }
4647
}

tests/ui/trivially_copy_pass_by_ref.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ fn good_return_explicit_lt_ref<'a>(foo: &'a Foo) -> &'a u32 {
4141
&foo.0
4242
}
4343

44+
#[allow(mismatched_lifetime_syntaxes)]
4445
fn good_return_implicit_lt_struct(foo: &Foo) -> FooRef {
4546
FooRef { foo }
4647
}

tests/ui/trivially_copy_pass_by_ref.stderr

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
2-
--> tests/ui/trivially_copy_pass_by_ref.rs:53:11
2+
--> tests/ui/trivially_copy_pass_by_ref.rs:54:11
33
|
44
LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
55
| ^^^^ help: consider passing by value instead: `u32`
@@ -11,103 +11,103 @@ LL | #![deny(clippy::trivially_copy_pass_by_ref)]
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1212

1313
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
14-
--> tests/ui/trivially_copy_pass_by_ref.rs:53:20
14+
--> tests/ui/trivially_copy_pass_by_ref.rs:54:20
1515
|
1616
LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
1717
| ^^^^ help: consider passing by value instead: `Foo`
1818

1919
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
20-
--> tests/ui/trivially_copy_pass_by_ref.rs:53:29
20+
--> tests/ui/trivially_copy_pass_by_ref.rs:54:29
2121
|
2222
LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
2323
| ^^^^ help: consider passing by value instead: `Baz`
2424

2525
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
26-
--> tests/ui/trivially_copy_pass_by_ref.rs:63:12
26+
--> tests/ui/trivially_copy_pass_by_ref.rs:64:12
2727
|
2828
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
2929
| ^^^^^ help: consider passing by value instead: `self`
3030

3131
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
32-
--> tests/ui/trivially_copy_pass_by_ref.rs:63:22
32+
--> tests/ui/trivially_copy_pass_by_ref.rs:64:22
3333
|
3434
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
3535
| ^^^^ help: consider passing by value instead: `u32`
3636

3737
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
38-
--> tests/ui/trivially_copy_pass_by_ref.rs:63:31
38+
--> tests/ui/trivially_copy_pass_by_ref.rs:64:31
3939
|
4040
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
4141
| ^^^^ help: consider passing by value instead: `Foo`
4242

4343
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
44-
--> tests/ui/trivially_copy_pass_by_ref.rs:63:40
44+
--> tests/ui/trivially_copy_pass_by_ref.rs:64:40
4545
|
4646
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
4747
| ^^^^ help: consider passing by value instead: `Baz`
4848

4949
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
50-
--> tests/ui/trivially_copy_pass_by_ref.rs:69:16
50+
--> tests/ui/trivially_copy_pass_by_ref.rs:70:16
5151
|
5252
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
5353
| ^^^^ help: consider passing by value instead: `u32`
5454

5555
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
56-
--> tests/ui/trivially_copy_pass_by_ref.rs:69:25
56+
--> tests/ui/trivially_copy_pass_by_ref.rs:70:25
5757
|
5858
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
5959
| ^^^^ help: consider passing by value instead: `Foo`
6060

6161
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
62-
--> tests/ui/trivially_copy_pass_by_ref.rs:69:34
62+
--> tests/ui/trivially_copy_pass_by_ref.rs:70:34
6363
|
6464
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
6565
| ^^^^ help: consider passing by value instead: `Baz`
6666

6767
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
68-
--> tests/ui/trivially_copy_pass_by_ref.rs:74:35
68+
--> tests/ui/trivially_copy_pass_by_ref.rs:75:35
6969
|
7070
LL | fn bad_issue7518(self, other: &Self) {}
7171
| ^^^^^ help: consider passing by value instead: `Self`
7272

7373
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
74-
--> tests/ui/trivially_copy_pass_by_ref.rs:87:16
74+
--> tests/ui/trivially_copy_pass_by_ref.rs:88:16
7575
|
7676
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
7777
| ^^^^ help: consider passing by value instead: `u32`
7878

7979
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
80-
--> tests/ui/trivially_copy_pass_by_ref.rs:87:25
80+
--> tests/ui/trivially_copy_pass_by_ref.rs:88:25
8181
|
8282
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
8383
| ^^^^ help: consider passing by value instead: `Foo`
8484

8585
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
86-
--> tests/ui/trivially_copy_pass_by_ref.rs:87:34
86+
--> tests/ui/trivially_copy_pass_by_ref.rs:88:34
8787
|
8888
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
8989
| ^^^^ help: consider passing by value instead: `Baz`
9090

9191
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
92-
--> tests/ui/trivially_copy_pass_by_ref.rs:94:33
92+
--> tests/ui/trivially_copy_pass_by_ref.rs:95:33
9393
|
9494
LL | fn trait_method(&self, foo: &Foo);
9595
| ^^^^ help: consider passing by value instead: `Foo`
9696

9797
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
98-
--> tests/ui/trivially_copy_pass_by_ref.rs:132:21
98+
--> tests/ui/trivially_copy_pass_by_ref.rs:133:21
9999
|
100100
LL | fn foo_never(x: &i32) {
101101
| ^^^^ help: consider passing by value instead: `i32`
102102

103103
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
104-
--> tests/ui/trivially_copy_pass_by_ref.rs:138:15
104+
--> tests/ui/trivially_copy_pass_by_ref.rs:139:15
105105
|
106106
LL | fn foo(x: &i32) {
107107
| ^^^^ help: consider passing by value instead: `i32`
108108

109109
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
110-
--> tests/ui/trivially_copy_pass_by_ref.rs:164:36
110+
--> tests/ui/trivially_copy_pass_by_ref.rs:165:36
111111
|
112112
LL | fn unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 {
113113
| ^^^^^^^ help: consider passing by value instead: `u32`

tests/ui/use_self.fixed

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ mod lifetimes {
6969
impl<'a> Foo<'a> {
7070
// Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
7171
// Foo<'b>`
72-
fn foo(s: &str) -> Foo {
72+
fn foo(s: &str) -> Foo<'_> {
7373
Foo { foo_str: s }
7474
}
7575
// cannot replace with `Self`, because that's `Foo<'a>`

tests/ui/use_self.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ mod lifetimes {
6969
impl<'a> Foo<'a> {
7070
// Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
7171
// Foo<'b>`
72-
fn foo(s: &str) -> Foo {
72+
fn foo(s: &str) -> Foo<'_> {
7373
Foo { foo_str: s }
7474
}
7575
// cannot replace with `Self`, because that's `Foo<'a>`

0 commit comments

Comments
 (0)