Skip to content

Commit

Permalink
Make closures and generators a must use types
Browse files Browse the repository at this point in the history
Warn about unused expressions with closure or generator type. This follows
existing precedence of must use annotations present on `FnOnce`, `FnMut`, `Fn`
traits, which already indirectly apply to closures in some cases, e.g.,:

```rust
fn f() -> impl FnOnce() {
    || {}
}

fn main() {
    // an existing warning: unused implementer of `std::ops::FnOnce` that must be used:
    f();

    // a new warning: unused closure that must be used:
    || {};
}
```
  • Loading branch information
tmiasko committed Jul 28, 2020
1 parent 1f5d69d commit 821d50a
Show file tree
Hide file tree
Showing 36 changed files with 355 additions and 31 deletions.
22 changes: 22 additions & 0 deletions src/librustc_lint/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,28 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
// Otherwise, we don't lint, to avoid false positives.
_ => false,
},
ty::Closure(..) => {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let mut err = lint.build(&format!(
"unused {}closure{}{} that must be used",
descr_pre, plural_suffix, descr_post,
));
err.note("closures are lazy and do nothing unless called");
err.emit();
});
true
}
ty::Generator(..) => {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let mut err = lint.build(&format!(
"unused {}generator{}{} that must be used",
descr_pre, plural_suffix, descr_post,
));
err.note("generators are lazy and do nothing unless resumed");
err.emit();
});
true
}
_ => false,
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/generator/issue-52398.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ impl A {
fn main() {
// Test that the MIR local with type &A created for the auto-borrow adjustment
// is caught by typeck
move || {
move || { //~ WARN unused generator that must be used
A.test(yield);
};

// Test that the std::cell::Ref temporary returned from the `borrow` call
// is caught by typeck
let y = RefCell::new(true);
static move || {
static move || { //~ WARN unused generator that must be used
yield *y.borrow();
return "Done";
};
Expand Down
24 changes: 24 additions & 0 deletions src/test/ui/generator/issue-52398.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
warning: unused generator that must be used
--> $DIR/issue-52398.rs:17:5
|
LL | / move || {
LL | | A.test(yield);
LL | | };
| |______^
|
= note: `#[warn(unused_must_use)]` on by default
= note: generators are lazy and do nothing unless resumed

warning: unused generator that must be used
--> $DIR/issue-52398.rs:24:5
|
LL | / static move || {
LL | | yield *y.borrow();
LL | | return "Done";
LL | | };
| |______^
|
= note: generators are lazy and do nothing unless resumed

warning: 2 warnings emitted

2 changes: 1 addition & 1 deletion src/test/ui/generator/issue-57084.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ where F: Fn() -> ()

fn main() {
let data = &vec![1];
|| {
|| { //~ WARN unused generator that must be used
let _to_pin = with(move || println!("{:p}", data));
loop {
yield
Expand Down
16 changes: 16 additions & 0 deletions src/test/ui/generator/issue-57084.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
warning: unused generator that must be used
--> $DIR/issue-57084.rs:22:5
|
LL | / || {
LL | | let _to_pin = with(move || println!("{:p}", data));
LL | | loop {
LL | | yield
LL | | }
LL | | };
| |______^
|
= note: `#[warn(unused_must_use)]` on by default
= note: generators are lazy and do nothing unless resumed

warning: 1 warning emitted

2 changes: 1 addition & 1 deletion src/test/ui/generator/match-bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ enum Enum {
}

fn main() {
|| {
|| { //~ WARN unused generator that must be used
loop {
if let true = true {
match Enum::A(String::new()) {
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/generator/match-bindings.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
warning: unused generator that must be used
--> $DIR/match-bindings.rs:12:5
|
LL | / || {
LL | | loop {
LL | | if let true = true {
LL | | match Enum::A(String::new()) {
... |
LL | | }
LL | | };
| |______^
|
= note: `#[warn(unused_must_use)]` on by default
= note: generators are lazy and do nothing unless resumed

warning: 1 warning emitted

2 changes: 1 addition & 1 deletion src/test/ui/generator/reborrow-mut-upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#![feature(generators)]

fn _run(bar: &mut i32) {
|| {
|| { //~ WARN unused generator that must be used
{
let _baz = &*bar;
yield;
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/generator/reborrow-mut-upvar.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
warning: unused generator that must be used
--> $DIR/reborrow-mut-upvar.rs:6:5
|
LL | / || {
LL | | {
LL | | let _baz = &*bar;
LL | | yield;
... |
LL | | *bar = 2;
LL | | };
| |______^
|
= note: `#[warn(unused_must_use)]` on by default
= note: generators are lazy and do nothing unless resumed

warning: 1 warning emitted

2 changes: 1 addition & 1 deletion src/test/ui/generator/too-live-local-in-immovable-gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

fn main() {
unsafe {
static move || {
static move || { //~ WARN unused generator that must be used
// Tests that the generator transformation finds out that `a` is not live
// during the yield expression. Type checking will also compute liveness
// and it should also find out that `a` is not live.
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/generator/too-live-local-in-immovable-gen.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
warning: unused generator that must be used
--> $DIR/too-live-local-in-immovable-gen.rs:8:9
|
LL | / static move || {
LL | | // Tests that the generator transformation finds out that `a` is not live
LL | | // during the yield expression. Type checking will also compute liveness
LL | | // and it should also find out that `a` is not live.
... |
LL | | &a;
LL | | };
| |__________^
|
= note: `#[warn(unused_must_use)]` on by default
= note: generators are lazy and do nothing unless resumed

warning: 1 warning emitted

2 changes: 1 addition & 1 deletion src/test/ui/generator/yield-in-args-rev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
fn foo(_a: (), _b: &bool) {}

fn bar() {
|| {
|| { //~ WARN unused generator that must be used
let b = true;
foo(yield, &b);
};
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/generator/yield-in-args-rev.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
warning: unused generator that must be used
--> $DIR/yield-in-args-rev.rs:13:5
|
LL | / || {
LL | | let b = true;
LL | | foo(yield, &b);
LL | | };
| |______^
|
= note: `#[warn(unused_must_use)]` on by default
= note: generators are lazy and do nothing unless resumed

warning: 1 warning emitted

2 changes: 1 addition & 1 deletion src/test/ui/generator/yield-in-box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

fn main() {
let x = 0i32;
|| {
|| { //~ WARN unused generator that must be used
let y = 2u32;
{
let _t = box (&x, yield 0, &y);
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/generator/yield-in-box.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
warning: unused generator that must be used
--> $DIR/yield-in-box.rs:9:5
|
LL | / || {
LL | | let y = 2u32;
LL | | {
LL | | let _t = box (&x, yield 0, &y);
... |
LL | | }
LL | | };
| |______^
|
= note: `#[warn(unused_must_use)]` on by default
= note: generators are lazy and do nothing unless resumed

warning: 1 warning emitted

2 changes: 1 addition & 1 deletion src/test/ui/generator/yield-in-initializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#![feature(generators)]

fn main() {
static || {
static || { //~ WARN unused generator that must be used
loop {
// Test that `opt` is not live across the yield, even when borrowed in a loop
// See https://github.com/rust-lang/rust/issues/52792
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/generator/yield-in-initializer.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
warning: unused generator that must be used
--> $DIR/yield-in-initializer.rs:6:5
|
LL | / static || {
LL | | loop {
LL | | // Test that `opt` is not live across the yield, even when borrowed in a loop
LL | | // See https://github.com/rust-lang/rust/issues/52792
... |
LL | | }
LL | | };
| |______^
|
= note: `#[warn(unused_must_use)]` on by default
= note: generators are lazy and do nothing unless resumed

warning: 1 warning emitted

2 changes: 1 addition & 1 deletion src/test/ui/generator/yield-subtype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn bar<'a>() {
let a: &'static str = "hi";
let b: &'a str = a;

|| {
|| { //~ WARN unused generator that must be used
yield a;
yield b;
};
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/generator/yield-subtype.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
warning: unused generator that must be used
--> $DIR/yield-subtype.rs:11:5
|
LL | / || {
LL | | yield a;
LL | | yield b;
LL | | };
| |______^
|
= note: `#[warn(unused_must_use)]` on by default
= note: generators are lazy and do nothing unless resumed

warning: 1 warning emitted

2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-1460.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
// pretty-expanded FIXME #23616

pub fn main() {
{|i: u32| if 1 == i { }};
{|i: u32| if 1 == i { }}; //~ WARN unused closure that must be used
}
11 changes: 11 additions & 0 deletions src/test/ui/issues/issue-1460.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
warning: unused closure that must be used
--> $DIR/issue-1460.rs:6:5
|
LL | {|i: u32| if 1 == i { }};
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_must_use)]` on by default
= note: closures are lazy and do nothing unless called

warning: 1 warning emitted

2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-16256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

fn main() {
let mut buf = Vec::new();
|c: u8| buf.push(c);
|c: u8| buf.push(c); //~ WARN unused closure that must be used
}
11 changes: 11 additions & 0 deletions src/test/ui/issues/issue-16256.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
warning: unused closure that must be used
--> $DIR/issue-16256.rs:6:5
|
LL | |c: u8| buf.push(c);
| ^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_must_use)]` on by default
= note: closures are lazy and do nothing unless called

warning: 1 warning emitted

18 changes: 9 additions & 9 deletions src/test/ui/liveness/liveness-upvars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn f() {
let mut c = 0;

// Captured by value, but variable is dead on entry.
move || {
let _ = move || {
c = 1; //~ WARN value captured by `c` is never read
println!("{}", c);
};
Expand All @@ -37,21 +37,21 @@ pub fn f() {
};

// Read and written to, but never actually used.
move || {
let _ = move || {
c += 1; //~ WARN unused variable: `c`
};
let _ = async move {
c += 1; //~ WARN value assigned to `c` is never read
//~| WARN unused variable: `c`
};

move || {
let _ = move || {
println!("{}", c);
// Value is read by closure itself on later invocations.
c += 1;
};
let b = Box::new(42);
move || {
let _ = move || {
println!("{}", c);
// Never read because this is FnOnce closure.
c += 1; //~ WARN value assigned to `c` is never read
Expand All @@ -67,12 +67,12 @@ pub fn f() {
pub fn nested() {
let mut d = None;
let mut e = None;
|| {
|| {
let _ = || {
let _ = || {
d = Some("d1"); //~ WARN value assigned to `d` is never read
d = Some("d2");
};
move || {
let _ = move || {
e = Some("e1"); //~ WARN value assigned to `e` is never read
//~| WARN unused variable: `e`
e = Some("e2"); //~ WARN value assigned to `e` is never read
Expand All @@ -81,7 +81,7 @@ pub fn nested() {
}

pub fn g<T: Default>(mut v: T) {
|r| {
let _ = |r| {
if r {
v = T::default(); //~ WARN value assigned to `v` is never read
} else {
Expand All @@ -92,7 +92,7 @@ pub fn g<T: Default>(mut v: T) {

pub fn h<T: Copy + Default + std::fmt::Debug>() {
let mut z = T::default();
move |b| {
let _ = move |b| {
loop {
if b {
z = T::default(); //~ WARN value assigned to `z` is never read
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/nll/capture-mut-ref.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
pub fn mutable_upvar() {
let x = &mut 0;
//~^ ERROR
move || {
let _ = move || {
*x = 1;
};
}
Expand Down
Loading

0 comments on commit 821d50a

Please sign in to comment.