Skip to content

Commit 57a6c89

Browse files
And finally add tests
1 parent e31df55 commit 57a6c89

File tree

4 files changed

+199
-15
lines changed

4 files changed

+199
-15
lines changed

compiler/rustc_lint/src/impl_trait_overcaptures.rs

+66-15
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,81 @@ use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
99
use rustc_middle::ty::{
1010
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
1111
};
12-
use rustc_session::lint::FutureIncompatibilityReason;
13-
use rustc_span::edition::Edition;
14-
use rustc_span::{BytePos, Span};
12+
use rustc_span::{sym, BytePos, Span};
1513

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

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

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

3989
declare_lint_pass!(
@@ -106,7 +156,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
106156
for arg in t.bound_vars() {
107157
let arg: ty::BoundVariableKind = arg;
108158
match arg {
109-
ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(def_id, ..)) => {
159+
ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(def_id, ..))
160+
| ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, _)) => {
110161
added.push(def_id);
111162
let unique = self.in_scope_parameters.insert(def_id);
112163
assert!(unique);
@@ -265,7 +316,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
265316
}
266317
_ => {
267318
self.tcx.dcx().span_delayed_bug(
268-
self.tcx().hir().span(arg.hir_id()),
319+
self.tcx.hir().span(arg.hir_id()),
269320
"no valid for captured arg",
270321
);
271322
}
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)