Skip to content

Commit 652ac8f

Browse files
committed
in which we lint #[must_use] functions with discardable return type
Resolves rust-lang#54828.
1 parent 4efdc04 commit 652ac8f

File tree

4 files changed

+120
-1
lines changed

4 files changed

+120
-1
lines changed

src/librustc_lint/unused.rs

+40
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,46 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
252252
debug!("Attr was used: {:?}", attr);
253253
}
254254
}
255+
256+
fn check_fn(&mut self,
257+
cx: &LateContext<'_, 'tcx>,
258+
fk: hir::intravisit::FnKind<'tcx>,
259+
decl: &hir::FnDecl,
260+
_: &hir::Body,
261+
_: Span,
262+
_: ast::NodeId) {
263+
if let Some(attr) = fk.attrs().iter().find(|attr| attr.check_name("must_use")) {
264+
// `#[must_use]` in particular is useless/unused on functions that
265+
// return `()` or "return" `!`-likes (Issue #54828)
266+
let (useless_must_use, ty_repr) = match &decl.output {
267+
hir::FunctionRetTy::DefaultReturn(_) => (true, "()".to_owned()),
268+
hir::FunctionRetTy::Return(ty) => {
269+
// The reason we're not sharing code from the UnusedResults
270+
// pass is because here these are `hir::Ty`s, not `ty::Ty`s
271+
let useless = match &ty.node {
272+
hir::TyKind::Tup(tys) => tys.is_empty(),
273+
hir::TyKind::Never => true,
274+
_ => false
275+
};
276+
let repr = hir::print::to_string(hir::print::NO_ANN, |s| s.print_type(&ty));
277+
(useless, repr)
278+
}
279+
};
280+
if useless_must_use {
281+
let mut err = cx.struct_span_lint(
282+
UNUSED_ATTRIBUTES, attr.span, "unused attribute"
283+
);
284+
err.span_label(
285+
decl.output.span(),
286+
format!("the return type `{}` can be discarded", ty_repr)
287+
);
288+
err.span_suggestion_short_with_applicability(
289+
attr.span, "remove it", String::new(), Applicability::MaybeIncorrect
290+
);
291+
err.emit();
292+
}
293+
}
294+
}
255295
}
256296

257297
declare_lint! {

src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ mod deprecated {
648648
mod must_use {
649649
mod inner { #![must_use="1400"] }
650650

651-
#[must_use = "1400"] fn f() { }
651+
#[must_use = "1400"] fn f() -> usize { 1 }
652652

653653
#[must_use = "1400"] struct S;
654654

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#![allow(dead_code)]
2+
#![deny(unused_attributes)]
3+
4+
#[must_use]
5+
fn truth() {}
6+
7+
#[must_use]
8+
fn pain() -> () {}
9+
10+
#[must_use]
11+
fn dignity() -> ! { panic!("despair"); }
12+
13+
struct Fear{}
14+
15+
impl Fear {
16+
#[must_use] fn bravery() {}
17+
}
18+
19+
trait Suspicion {
20+
#[must_use] fn inspect();
21+
}
22+
23+
impl Suspicion for Fear {
24+
// FIXME: it's actually rather problematic for this to get the unused-attributes
25+
// lint on account of the return type—the unused-attributes lint should fire
26+
// here, but it should be because `#[must_use]` needs to go on the trait
27+
// definition, not the impl (Issue #48486)
28+
#[must_use] fn inspect() {}
29+
}
30+
31+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
error: unused attribute
2+
--> $DIR/issue-54828-unused-must-use-attribute.rs:4:1
3+
|
4+
LL | #[must_use]
5+
| ^^^^^^^^^^^ help: remove it
6+
LL | fn truth() {}
7+
| - the return type `()` can be discarded
8+
|
9+
note: lint level defined here
10+
--> $DIR/issue-54828-unused-must-use-attribute.rs:2:9
11+
|
12+
LL | #![deny(unused_attributes)]
13+
| ^^^^^^^^^^^^^^^^^
14+
15+
error: unused attribute
16+
--> $DIR/issue-54828-unused-must-use-attribute.rs:7:1
17+
|
18+
LL | #[must_use]
19+
| ^^^^^^^^^^^ help: remove it
20+
LL | fn pain() -> () {}
21+
| -- the return type `()` can be discarded
22+
23+
error: unused attribute
24+
--> $DIR/issue-54828-unused-must-use-attribute.rs:10:1
25+
|
26+
LL | #[must_use]
27+
| ^^^^^^^^^^^ help: remove it
28+
LL | fn dignity() -> ! { panic!("despair"); }
29+
| - the return type `!` can be discarded
30+
31+
error: unused attribute
32+
--> $DIR/issue-54828-unused-must-use-attribute.rs:16:5
33+
|
34+
LL | #[must_use] fn bravery() {}
35+
| ^^^^^^^^^^^ - the return type `()` can be discarded
36+
| |
37+
| help: remove it
38+
39+
error: unused attribute
40+
--> $DIR/issue-54828-unused-must-use-attribute.rs:28:5
41+
|
42+
LL | #[must_use] fn inspect() {}
43+
| ^^^^^^^^^^^ - the return type `()` can be discarded
44+
| |
45+
| help: remove it
46+
47+
error: aborting due to 5 previous errors
48+

0 commit comments

Comments
 (0)