Skip to content

Commit

Permalink
in which we lint #[must_use] functions with discardable return type
Browse files Browse the repository at this point in the history
Resolves rust-lang#54828.
  • Loading branch information
zackmdavis committed Oct 7, 2018
1 parent 4efdc04 commit 652ac8f
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 1 deletion.
40 changes: 40 additions & 0 deletions src/librustc_lint/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,46 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
debug!("Attr was used: {:?}", attr);
}
}

fn check_fn(&mut self,
cx: &LateContext<'_, 'tcx>,
fk: hir::intravisit::FnKind<'tcx>,
decl: &hir::FnDecl,
_: &hir::Body,
_: Span,
_: ast::NodeId) {
if let Some(attr) = fk.attrs().iter().find(|attr| attr.check_name("must_use")) {
// `#[must_use]` in particular is useless/unused on functions that
// return `()` or "return" `!`-likes (Issue #54828)
let (useless_must_use, ty_repr) = match &decl.output {
hir::FunctionRetTy::DefaultReturn(_) => (true, "()".to_owned()),
hir::FunctionRetTy::Return(ty) => {
// The reason we're not sharing code from the UnusedResults
// pass is because here these are `hir::Ty`s, not `ty::Ty`s
let useless = match &ty.node {
hir::TyKind::Tup(tys) => tys.is_empty(),
hir::TyKind::Never => true,
_ => false
};
let repr = hir::print::to_string(hir::print::NO_ANN, |s| s.print_type(&ty));
(useless, repr)
}
};
if useless_must_use {
let mut err = cx.struct_span_lint(
UNUSED_ATTRIBUTES, attr.span, "unused attribute"
);
err.span_label(
decl.output.span(),
format!("the return type `{}` can be discarded", ty_repr)
);
err.span_suggestion_short_with_applicability(
attr.span, "remove it", String::new(), Applicability::MaybeIncorrect
);
err.emit();
}
}
}
}

declare_lint! {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ mod deprecated {
mod must_use {
mod inner { #![must_use="1400"] }

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

#[must_use = "1400"] struct S;

Expand Down
31 changes: 31 additions & 0 deletions src/test/ui/lint/issue-54828-unused-must-use-attribute.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#![allow(dead_code)]
#![deny(unused_attributes)]

#[must_use]
fn truth() {}

#[must_use]
fn pain() -> () {}

#[must_use]
fn dignity() -> ! { panic!("despair"); }

struct Fear{}

impl Fear {
#[must_use] fn bravery() {}
}

trait Suspicion {
#[must_use] fn inspect();
}

impl Suspicion for Fear {
// FIXME: it's actually rather problematic for this to get the unused-attributes
// lint on account of the return type—the unused-attributes lint should fire
// here, but it should be because `#[must_use]` needs to go on the trait
// definition, not the impl (Issue #48486)
#[must_use] fn inspect() {}
}

fn main() {}
48 changes: 48 additions & 0 deletions src/test/ui/lint/issue-54828-unused-must-use-attribute.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
error: unused attribute
--> $DIR/issue-54828-unused-must-use-attribute.rs:4:1
|
LL | #[must_use]
| ^^^^^^^^^^^ help: remove it
LL | fn truth() {}
| - the return type `()` can be discarded
|
note: lint level defined here
--> $DIR/issue-54828-unused-must-use-attribute.rs:2:9
|
LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^

error: unused attribute
--> $DIR/issue-54828-unused-must-use-attribute.rs:7:1
|
LL | #[must_use]
| ^^^^^^^^^^^ help: remove it
LL | fn pain() -> () {}
| -- the return type `()` can be discarded

error: unused attribute
--> $DIR/issue-54828-unused-must-use-attribute.rs:10:1
|
LL | #[must_use]
| ^^^^^^^^^^^ help: remove it
LL | fn dignity() -> ! { panic!("despair"); }
| - the return type `!` can be discarded

error: unused attribute
--> $DIR/issue-54828-unused-must-use-attribute.rs:16:5
|
LL | #[must_use] fn bravery() {}
| ^^^^^^^^^^^ - the return type `()` can be discarded
| |
| help: remove it

error: unused attribute
--> $DIR/issue-54828-unused-must-use-attribute.rs:28:5
|
LL | #[must_use] fn inspect() {}
| ^^^^^^^^^^^ - the return type `()` can be discarded
| |
| help: remove it

error: aborting due to 5 previous errors

0 comments on commit 652ac8f

Please sign in to comment.