Skip to content

Commit 6f055bd

Browse files
And finally add tests
1 parent ff76eab commit 6f055bd

File tree

4 files changed

+195
-15
lines changed

4 files changed

+195
-15
lines changed

compiler/rustc_lint/src/impl_trait_overcaptures.rs

+62-15
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,77 @@ use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
1010
use rustc_middle::ty::{
1111
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
1212
};
13-
use rustc_session::lint::FutureIncompatibilityReason;
14-
use rustc_span::edition::Edition;
15-
use rustc_span::{BytePos, Span};
13+
use rustc_span::{sym, BytePos, Span};
1614

1715
use crate::fluent_generated as fluent;
1816
use crate::{LateContext, LateLintPass};
1917

20-
// TODO: feature gate these too
21-
2218
declare_lint! {
23-
/// UwU
19+
/// In the 2024 edition, `impl Trait`s will capture all lifetimes in scope,
20+
/// rather than just the lifetimes that are mentioned in the bounds of the type.
21+
/// Often these sets are equal, but if not, it means that the `impl Trait` may
22+
/// cause erroneous borrow-checker errors.
23+
///
24+
/// ### Example
25+
///
26+
/// ```rust,compile_fail
27+
/// # #![feature(precise_capturing, lifetime_capture_rules_2024)]
28+
/// # use std::fmt::Display;
29+
/// let mut x = vec![];
30+
/// x.push(1);
31+
///
32+
/// fn test(x: &Vec<i32>) -> impl Display {
33+
/// x[0]
34+
/// }
35+
///
36+
/// let element = test(&x);
37+
/// x.push(2);
38+
/// println!("{element}");
39+
/// ```
40+
///
41+
/// {{produces}}
42+
///
43+
/// ### Explanation
44+
///
45+
/// In edition < 2024, the returned `impl Display` doesn't capture the
46+
/// lifetime from the `&Vec<i32>`, so the vector can be mutably borrowed
47+
/// while the `impl Display` is live.
48+
///
49+
/// To fix this, we can explicitly state that the `impl Display` doesn't
50+
/// capture any lifetimes, using `impl use<> Display`.
2451
pub IMPL_TRAIT_OVERCAPTURES,
2552
Allow,
26-
"will capture more lifetimes than possibly intended in edition 2024",
27-
@future_incompatible = FutureIncompatibleInfo {
28-
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
29-
reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
30-
};
53+
"`impl Trait` will capture more lifetimes than possibly intended in edition 2024",
54+
@feature_gate = sym::precise_capturing;
55+
//@future_incompatible = FutureIncompatibleInfo {
56+
// reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
57+
// reference: "<FIXME>",
58+
//};
3159
}
3260

3361
declare_lint! {
34-
/// UwU
62+
/// In the 2024 edition, `impl Trait`s will capture all lifetimes in scope.
63+
/// If precise-capturing `use<...>` syntax is used, and the set of parameters
64+
/// that are captures are *equal* to the set of parameters in scope, then
65+
/// the syntax is redundant, and can be removed.
66+
///
67+
/// ### Example
68+
///
69+
/// ```rust,compile_fail
70+
/// # #![feature(precise_capturing, lifetime_capture_rules_2024)]
71+
/// fn test<'a>(x: &'a i32) -> impl use<'a> Sized { x }
72+
/// ```
73+
///
74+
/// {{produces}}
75+
///
76+
/// ### Explanation
77+
///
78+
/// To fix this, remove the `use<'a>`, since the lifetime is already captured
79+
/// since it is in scope.
3580
pub IMPL_TRAIT_REDUNDANT_CAPTURES,
3681
Warn,
37-
"uwu 2"
82+
"redundant precise-capturing `use<...>` syntax on an `impl Trait`",
83+
@feature_gate = sym::precise_capturing;
3884
}
3985

4086
declare_lint_pass!(
@@ -116,7 +162,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
116162
for arg in t.bound_vars() {
117163
let arg: ty::BoundVariableKind = arg;
118164
match arg {
119-
ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(def_id, ..)) => {
165+
ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(def_id, ..))
166+
| ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, _)) => {
120167
added.push(def_id);
121168
let unique = self.in_scope_parameters.insert(def_id);
122169
assert!(unique);
@@ -267,7 +314,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
267314
}
268315
_ => {
269316
self.tcx.dcx().span_delayed_bug(
270-
self.tcx().hir().span(arg.hir_id()),
317+
self.tcx.hir().span(arg.hir_id()),
271318
"no valid for captured arg",
272319
);
273320
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ run-rustfix
2+
3+
#![feature(precise_capturing)]
4+
#![allow(unused, incomplete_features)]
5+
#![deny(impl_trait_overcaptures)]
6+
7+
fn named<'a>(x: &'a i32) -> impl use<> Sized { *x }
8+
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
9+
10+
fn implicit(x: &i32) -> impl use<> Sized { *x }
11+
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
12+
13+
struct W;
14+
impl W {
15+
fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self }
16+
//~^ ERROR `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
17+
}
18+
19+
trait Higher<'a> {
20+
type Output;
21+
}
22+
impl Higher<'_> for () {
23+
type Output = ();
24+
}
25+
26+
fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {}
27+
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
28+
29+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ run-rustfix
2+
3+
#![feature(precise_capturing)]
4+
#![allow(unused, incomplete_features)]
5+
#![deny(impl_trait_overcaptures)]
6+
7+
fn named<'a>(x: &'a i32) -> impl Sized { *x }
8+
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
9+
10+
fn implicit(x: &i32) -> impl Sized { *x }
11+
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
12+
13+
struct W;
14+
impl W {
15+
fn hello(&self, x: &i32) -> impl Sized + '_ { self }
16+
//~^ ERROR `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
17+
}
18+
19+
trait Higher<'a> {
20+
type Output;
21+
}
22+
impl Higher<'_> for () {
23+
type Output = ();
24+
}
25+
26+
fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
27+
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
28+
29+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
2+
--> $DIR/overcaptures-2024.rs:7:29
3+
|
4+
LL | fn named<'a>(x: &'a i32) -> impl Sized { *x }
5+
| ^^^^^^^^^^
6+
|
7+
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
8+
--> $DIR/overcaptures-2024.rs:7:10
9+
|
10+
LL | fn named<'a>(x: &'a i32) -> impl Sized { *x }
11+
| ^^
12+
= note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
13+
note: the lint level is defined here
14+
--> $DIR/overcaptures-2024.rs:5:9
15+
|
16+
LL | #![deny(impl_trait_overcaptures)]
17+
| ^^^^^^^^^^^^^^^^^^^^^^^
18+
help: use the precise capturing `use<...>` syntax to make the captures explicit
19+
|
20+
LL | fn named<'a>(x: &'a i32) -> impl use<> Sized { *x }
21+
| +++++
22+
23+
error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
24+
--> $DIR/overcaptures-2024.rs:10:25
25+
|
26+
LL | fn implicit(x: &i32) -> impl Sized { *x }
27+
| ^^^^^^^^^^
28+
|
29+
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
30+
--> $DIR/overcaptures-2024.rs:10:16
31+
|
32+
LL | fn implicit(x: &i32) -> impl Sized { *x }
33+
| ^
34+
= note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
35+
help: use the precise capturing `use<...>` syntax to make the captures explicit
36+
|
37+
LL | fn implicit(x: &i32) -> impl use<> Sized { *x }
38+
| +++++
39+
40+
error: `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
41+
--> $DIR/overcaptures-2024.rs:15:33
42+
|
43+
LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self }
44+
| ^^^^^^^^^^^^^^^
45+
|
46+
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
47+
--> $DIR/overcaptures-2024.rs:15:24
48+
|
49+
LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self }
50+
| ^
51+
= note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
52+
help: use the precise capturing `use<...>` syntax to make the captures explicit
53+
|
54+
LL | fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self }
55+
| +++++++
56+
57+
error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
58+
--> $DIR/overcaptures-2024.rs:26:47
59+
|
60+
LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
61+
| ^^^^^^^^^^
62+
|
63+
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
64+
--> $DIR/overcaptures-2024.rs:26:23
65+
|
66+
LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
67+
| ^^
68+
= note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
69+
help: use the precise capturing `use<...>` syntax to make the captures explicit
70+
|
71+
LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {}
72+
| +++++
73+
74+
error: aborting due to 4 previous errors
75+

0 commit comments

Comments
 (0)