Skip to content

Commit 85d9f17

Browse files
committed
Auto merge of #10589 - blyxyas:fix-double_must_use, r=giraffate
Mini-fix `double_must_use` for async functions From Rust 1.67 onwards, the `#[must_use]` attribute also applies to the `Future::Output` (rust-lang/rust#100633). So the lint `double_must_use` was linting all async functions. This PR changes the `double_must_use` lint so it ignores `async` functions. --- Closes #10486 changelog: [`double_must_use`]: Fix false positive in async function
2 parents 9e53b65 + a37eb4d commit 85d9f17

File tree

3 files changed

+35
-4
lines changed

3 files changed

+35
-4
lines changed

clippy_lints/src/functions/must_use.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
use hir::FnSig;
12
use rustc_ast::ast::Attribute;
23
use rustc_errors::Applicability;
34
use rustc_hir::def_id::DefIdSet;
45
use rustc_hir::{self as hir, def::Res, QPath};
6+
use rustc_infer::infer::TyCtxtInferExt;
57
use rustc_lint::{LateContext, LintContext};
68
use rustc_middle::{
79
lint::in_external_macro,
@@ -27,7 +29,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
2729
let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
2830
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
2931
if let Some(attr) = attr {
30-
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
32+
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig);
3133
} else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
3234
check_must_use_candidate(
3335
cx,
@@ -49,7 +51,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
4951
let attrs = cx.tcx.hir().attrs(item.hir_id());
5052
let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
5153
if let Some(attr) = attr {
52-
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
54+
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig);
5355
} else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
5456
check_must_use_candidate(
5557
cx,
@@ -72,7 +74,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
7274
let attrs = cx.tcx.hir().attrs(item.hir_id());
7375
let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
7476
if let Some(attr) = attr {
75-
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
77+
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig);
7678
} else if let hir::TraitFn::Provided(eid) = *eid {
7779
let body = cx.tcx.hir().body(eid);
7880
if attr.is_none() && is_public && !is_proc_macro(attrs) {
@@ -97,6 +99,7 @@ fn check_needless_must_use(
9799
item_span: Span,
98100
fn_header_span: Span,
99101
attr: &Attribute,
102+
sig: &FnSig<'_>,
100103
) {
101104
if in_external_macro(cx.sess(), item_span) {
102105
return;
@@ -112,6 +115,15 @@ fn check_needless_must_use(
112115
},
113116
);
114117
} else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
118+
// Ignore async functions unless Future::Output type is a must_use type
119+
if sig.header.is_async() {
120+
let infcx = cx.tcx.infer_ctxt().build();
121+
if let Some(future_ty) = infcx.get_impl_future_output_ty(return_ty(cx, item_id))
122+
&& !is_must_use_ty(cx, future_ty) {
123+
return;
124+
}
125+
}
126+
115127
span_lint_and_help(
116128
cx,
117129
DOUBLE_MUST_USE,

tests/ui/double_must_use.rs

+11
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@ pub fn must_use_with_note() -> Result<(), ()> {
2121
unimplemented!();
2222
}
2323

24+
// vvvv Should not lint (#10486)
25+
#[must_use]
26+
async fn async_must_use() -> usize {
27+
unimplemented!();
28+
}
29+
30+
#[must_use]
31+
async fn async_must_use_result() -> Result<(), ()> {
32+
Ok(())
33+
}
34+
2435
fn main() {
2536
must_use_result();
2637
must_use_tuple();

tests/ui/double_must_use.stderr

+9-1
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,13 @@ LL | pub fn must_use_array() -> [Result<(), ()>; 1] {
2323
|
2424
= help: either add some descriptive text or remove the attribute
2525

26-
error: aborting due to 3 previous errors
26+
error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`
27+
--> $DIR/double_must_use.rs:31:1
28+
|
29+
LL | async fn async_must_use_result() -> Result<(), ()> {
30+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31+
|
32+
= help: either add some descriptive text or remove the attribute
33+
34+
error: aborting due to 4 previous errors
2735

0 commit comments

Comments
 (0)