Skip to content

Commit 1fccd4c

Browse files
Add UI coverage for closure for<> binder binding suggestions
Cover MachineApplicable rewrites, MaybeIncorrect capture cases, and macro-expanded binders where structured suggestions must be suppressed. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent da0f869 commit 1fccd4c

9 files changed

Lines changed: 654 additions & 4 deletions
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//@ compile-flags: --error-format=json
2+
//@ forbid-output: MachineApplicable
3+
//@ forbid-output: MaybeIncorrect
4+
5+
// Macro-expanded closures must not get a structured fn-pointer rewrite (hygiene + spans point
6+
// into the macro). Expect only the simple help.
7+
8+
macro_rules! make {
9+
($x:ident) => {
10+
for<'a> |x: &'a i32| -> i32 { *x + $x }
11+
//~^ ERROR `for<...>` binders for closures are experimental
12+
//~| HELP add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
13+
//~| HELP consider removing `for<...>`
14+
};
15+
}
16+
17+
fn main() {
18+
let x = 1;
19+
let _cl = make!(x);
20+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{"$message_type":"diagnostic","message":"`for<...>` binders for closures are experimental","code":{"code":"E0658","explanation":"An unstable feature was used.
2+
3+
Erroneous code example:
4+
5+
```compile_fail,E0658
6+
use std::intrinsics; // error: use of unstable library feature `core_intrinsics`
7+
```
8+
9+
If you're using a stable or a beta version of rustc, you won't be able to use
10+
any unstable features. In order to do so, please switch to a nightly version of
11+
rustc (by using [rustup]).
12+
13+
If you're using a nightly version of rustc, just add the corresponding feature
14+
to be able to use it:
15+
16+
```
17+
#![feature(core_intrinsics)]
18+
19+
use std::intrinsics; // ok!
20+
```
21+
22+
[rustup]: https://rust-lang.github.io/rustup/concepts/channels.html
23+
"},"level":"error","spans":[{"file_name":"$DIR/feature-gate-closure_lifetime_binder-macro.rs","byte_start":304,"byte_end":311,"line_start":10,"line_end":10,"column_start":9,"column_end":16,"is_primary":true,"text":[{"text":" for<'a> |x: &'a i32| -> i32 { *x + $x }","highlight_start":9,"highlight_end":16}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":{"span":{"file_name":"$DIR/feature-gate-closure_lifetime_binder-macro.rs","byte_start":605,"byte_end":613,"line_start":19,"line_end":19,"column_start":15,"column_end":23,"is_primary":false,"text":[{"text":" let _cl = make!(x);","highlight_start":15,"highlight_end":23}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},"macro_decl_name":"make!","def_site_span":{"file_name":"$DIR/feature-gate-closure_lifetime_binder-macro.rs","byte_start":256,"byte_end":273,"line_start":8,"line_end":8,"column_start":1,"column_end":18,"is_primary":false,"text":[{"text":"macro_rules! make {","highlight_start":1,"highlight_end":18}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}}}],"children":[{"message":"see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider removing `for<...>`","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":"error[E0658]: `for<...>` binders for closures are experimental
24+
--> $DIR/feature-gate-closure_lifetime_binder-macro.rs:10:9
25+
|
26+
LL | for<'a> |x: &'a i32| -> i32 { *x + $x }
27+
| ^^^^^^^
28+
...
29+
LL | let _cl = make!(x);
30+
| -------- in this macro invocation
31+
|
32+
= note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
33+
= help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
34+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
35+
= help: consider removing `for<...>`
36+
= note: this error originates in the macro `make` (in Nightly builds, run with -Z macro-backtrace for more info)
37+
38+
"}
39+
{"$message_type":"diagnostic","message":"aborting due to 1 previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 1 previous error
40+
41+
"}
42+
{"$message_type":"diagnostic","message":"For more information about this error, try `rustc --explain E0658`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0658`.
43+
"}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//@ edition: 2024
2+
//@ compile-flags: --error-format=json
3+
//@ error-pattern: "suggestion_applicability":"MaybeIncorrect"
4+
5+
// Capturing closures must not get a MachineApplicable rewrite. Cover plain captures, let-else
6+
// leakage, and let-chain shadowing — all should report MaybeIncorrect in JSON.
7+
8+
fn main() {
9+
let y = 1;
10+
let _capture = for<'a> |x: &'a i32| -> i32 { *x + y };
11+
//~^ ERROR `for<...>` binders for closures are experimental
12+
13+
let let_else_env = 1;
14+
let _let_else = for<'a> |x: &'a i32| -> i32 {
15+
//~^ ERROR `for<...>` binders for closures are experimental
16+
let Some(_) = None::<i32> else {
17+
let let_else_env = 0;
18+
return let_else_env;
19+
};
20+
*x + let_else_env
21+
};
22+
23+
let chain_env = 1;
24+
let _let_chain = for<'a> |x: &'a i32| -> i32 {
25+
//~^ ERROR `for<...>` binders for closures are experimental
26+
if let Some(chain_env) = None::<i32>
27+
&& chain_env == 0
28+
{
29+
0
30+
} else {
31+
*x + chain_env
32+
}
33+
};
34+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
{"$message_type":"diagnostic","message":"`for<...>` binders for closures are experimental","code":{"code":"E0658","explanation":"An unstable feature was used.
2+
3+
Erroneous code example:
4+
5+
```compile_fail,E0658
6+
use std::intrinsics; // error: use of unstable library feature `core_intrinsics`
7+
```
8+
9+
If you're using a stable or a beta version of rustc, you won't be able to use
10+
any unstable features. In order to do so, please switch to a nightly version of
11+
rustc (by using [rustup]).
12+
13+
If you're using a nightly version of rustc, just add the corresponding feature
14+
to be able to use it:
15+
16+
```
17+
#![feature(core_intrinsics)]
18+
19+
use std::intrinsics; // ok!
20+
```
21+
22+
[rustup]: https://rust-lang.github.io/rustup/concepts/channels.html
23+
"},"level":"error","spans":[{"file_name":"$DIR/feature-gate-closure_lifetime_binder-maybe-incorrect.rs","byte_start":345,"byte_end":352,"line_start":10,"line_end":10,"column_start":20,"column_end":27,"is_primary":true,"text":[{"text":" let _capture = for<'a> |x: &'a i32| -> i32 { *x + y };","highlight_start":20,"highlight_end":27}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider setting the binding type instead","code":null,"level":"help","spans":[{"file_name":"$DIR/feature-gate-closure_lifetime_binder-maybe-incorrect.rs","byte_start":342,"byte_end":342,"line_start":10,"line_end":10,"column_start":17,"column_end":17,"is_primary":true,"text":[{"text":" let _capture = for<'a> |x: &'a i32| -> i32 { *x + y };","highlight_start":17,"highlight_end":17}],"label":null,"suggested_replacement":": for<'a> fn(&'a i32) -> i32","suggestion_applicability":"MaybeIncorrect","expansion":null},{"file_name":"$DIR/feature-gate-closure_lifetime_binder-maybe-incorrect.rs","byte_start":345,"byte_end":372,"line_start":10,"line_end":10,"column_start":20,"column_end":47,"is_primary":true,"text":[{"text":" let _capture = for<'a> |x: &'a i32| -> i32 { *x + y };","highlight_start":20,"highlight_end":47}],"label":null,"suggested_replacement":"|x|","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0658]: `for<...>` binders for closures are experimental
24+
--> $DIR/feature-gate-closure_lifetime_binder-maybe-incorrect.rs:10:20
25+
|
26+
LL | let _capture = for<'a> |x: &'a i32| -> i32 { *x + y };
27+
| ^^^^^^^
28+
|
29+
= note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
30+
= help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
31+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
32+
help: consider setting the binding type instead
33+
|
34+
LL - let _capture = for<'a> |x: &'a i32| -> i32 { *x + y };
35+
LL + let _capture: for<'a> fn(&'a i32) -> i32 = |x| { *x + y };
36+
|
37+
38+
"}
39+
{"$message_type":"diagnostic","message":"`for<...>` binders for closures are experimental","code":{"code":"E0658","explanation":"An unstable feature was used.
40+
41+
Erroneous code example:
42+
43+
```compile_fail,E0658
44+
use std::intrinsics; // error: use of unstable library feature `core_intrinsics`
45+
```
46+
47+
If you're using a stable or a beta version of rustc, you won't be able to use
48+
any unstable features. In order to do so, please switch to a nightly version of
49+
rustc (by using [rustup]).
50+
51+
If you're using a nightly version of rustc, just add the corresponding feature
52+
to be able to use it:
53+
54+
```
55+
#![feature(core_intrinsics)]
56+
57+
use std::intrinsics; // ok!
58+
```
59+
60+
[rustup]: https://rust-lang.github.io/rustup/concepts/channels.html
61+
"},"level":"error","spans":[{"file_name":"$DIR/feature-gate-closure_lifetime_binder-maybe-incorrect.rs","byte_start":496,"byte_end":503,"line_start":14,"line_end":14,"column_start":21,"column_end":28,"is_primary":true,"text":[{"text":" let _let_else = for<'a> |x: &'a i32| -> i32 {","highlight_start":21,"highlight_end":28}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider setting the binding type instead","code":null,"level":"help","spans":[{"file_name":"$DIR/feature-gate-closure_lifetime_binder-maybe-incorrect.rs","byte_start":493,"byte_end":493,"line_start":14,"line_end":14,"column_start":18,"column_end":18,"is_primary":true,"text":[{"text":" let _let_else = for<'a> |x: &'a i32| -> i32 {","highlight_start":18,"highlight_end":18}],"label":null,"suggested_replacement":": for<'a> fn(&'a i32) -> i32","suggestion_applicability":"MaybeIncorrect","expansion":null},{"file_name":"$DIR/feature-gate-closure_lifetime_binder-maybe-incorrect.rs","byte_start":496,"byte_end":523,"line_start":14,"line_end":14,"column_start":21,"column_end":48,"is_primary":true,"text":[{"text":" let _let_else = for<'a> |x: &'a i32| -> i32 {","highlight_start":21,"highlight_end":48}],"label":null,"suggested_replacement":"|x|","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0658]: `for<...>` binders for closures are experimental
62+
--> $DIR/feature-gate-closure_lifetime_binder-maybe-incorrect.rs:14:21
63+
|
64+
LL | let _let_else = for<'a> |x: &'a i32| -> i32 {
65+
| ^^^^^^^
66+
|
67+
= note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
68+
= help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
69+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
70+
help: consider setting the binding type instead
71+
|
72+
LL - let _let_else = for<'a> |x: &'a i32| -> i32 {
73+
LL + let _let_else: for<'a> fn(&'a i32) -> i32 = |x| {
74+
|
75+
76+
"}
77+
{"$message_type":"diagnostic","message":"`for<...>` binders for closures are experimental","code":{"code":"E0658","explanation":"An unstable feature was used.
78+
79+
Erroneous code example:
80+
81+
```compile_fail,E0658
82+
use std::intrinsics; // error: use of unstable library feature `core_intrinsics`
83+
```
84+
85+
If you're using a stable or a beta version of rustc, you won't be able to use
86+
any unstable features. In order to do so, please switch to a nightly version of
87+
rustc (by using [rustup]).
88+
89+
If you're using a nightly version of rustc, just add the corresponding feature
90+
to be able to use it:
91+
92+
```
93+
#![feature(core_intrinsics)]
94+
95+
use std::intrinsics; // ok!
96+
```
97+
98+
[rustup]: https://rust-lang.github.io/rustup/concepts/channels.html
99+
"},"level":"error","spans":[{"file_name":"$DIR/feature-gate-closure_lifetime_binder-maybe-incorrect.rs","byte_start":791,"byte_end":798,"line_start":24,"line_end":24,"column_start":22,"column_end":29,"is_primary":true,"text":[{"text":" let _let_chain = for<'a> |x: &'a i32| -> i32 {","highlight_start":22,"highlight_end":29}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider setting the binding type instead","code":null,"level":"help","spans":[{"file_name":"$DIR/feature-gate-closure_lifetime_binder-maybe-incorrect.rs","byte_start":788,"byte_end":788,"line_start":24,"line_end":24,"column_start":19,"column_end":19,"is_primary":true,"text":[{"text":" let _let_chain = for<'a> |x: &'a i32| -> i32 {","highlight_start":19,"highlight_end":19}],"label":null,"suggested_replacement":": for<'a> fn(&'a i32) -> i32","suggestion_applicability":"MaybeIncorrect","expansion":null},{"file_name":"$DIR/feature-gate-closure_lifetime_binder-maybe-incorrect.rs","byte_start":791,"byte_end":818,"line_start":24,"line_end":24,"column_start":22,"column_end":49,"is_primary":true,"text":[{"text":" let _let_chain = for<'a> |x: &'a i32| -> i32 {","highlight_start":22,"highlight_end":49}],"label":null,"suggested_replacement":"|x|","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0658]: `for<...>` binders for closures are experimental
100+
--> $DIR/feature-gate-closure_lifetime_binder-maybe-incorrect.rs:24:22
101+
|
102+
LL | let _let_chain = for<'a> |x: &'a i32| -> i32 {
103+
| ^^^^^^^
104+
|
105+
= note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
106+
= help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
107+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
108+
help: consider setting the binding type instead
109+
|
110+
LL - let _let_chain = for<'a> |x: &'a i32| -> i32 {
111+
LL + let _let_chain: for<'a> fn(&'a i32) -> i32 = |x| {
112+
|
113+
114+
"}
115+
{"$message_type":"diagnostic","message":"aborting due to 3 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 3 previous errors
116+
117+
"}
118+
{"$message_type":"diagnostic","message":"For more information about this error, try `rustc --explain E0658`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0658`.
119+
"}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@ run-rustfix
2+
//@ rustfix-only-machine-applicable
3+
4+
// Verify the #160431 rewrite is MachineApplicable: rustfix applies it and the result compiles
5+
// without `#![feature(closure_lifetime_binder)]`.
6+
7+
fn main() {
8+
let _cl: for<'a> fn(&'a str) -> (&'a str, &'a str) = |x| { x.split_at(0) };
9+
//~^ ERROR `for<...>` binders for closures are experimental
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@ run-rustfix
2+
//@ rustfix-only-machine-applicable
3+
4+
// Verify the #160431 rewrite is MachineApplicable: rustfix applies it and the result compiles
5+
// without `#![feature(closure_lifetime_binder)]`.
6+
7+
fn main() {
8+
let _cl = for<'a> |x: &'a str| -> (&'a str, &'a str) { x.split_at(0) };
9+
//~^ ERROR `for<...>` binders for closures are experimental
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0658]: `for<...>` binders for closures are experimental
2+
--> $DIR/feature-gate-closure_lifetime_binder-rustfix.rs:8:15
3+
|
4+
LL | let _cl = for<'a> |x: &'a str| -> (&'a str, &'a str) { x.split_at(0) };
5+
| ^^^^^^^
6+
|
7+
= note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
8+
= help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
help: consider setting the binding type instead
11+
|
12+
LL - let _cl = for<'a> |x: &'a str| -> (&'a str, &'a str) { x.split_at(0) };
13+
LL + let _cl: for<'a> fn(&'a str) -> (&'a str, &'a str) = |x| { x.split_at(0) };
14+
|
15+
16+
error: aborting due to 1 previous error
17+
18+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)