Skip to content

Commit

Permalink
Auto merge of #10589 - blyxyas:fix-double_must_use, r=giraffate
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Apr 4, 2023
2 parents 9e53b65 + a37eb4d commit 85d9f17
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 4 deletions.
18 changes: 15 additions & 3 deletions clippy_lints/src/functions/must_use.rs
@@ -1,7 +1,9 @@
use hir::FnSig;
use rustc_ast::ast::Attribute;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefIdSet;
use rustc_hir::{self as hir, def::Res, QPath};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LintContext};
use rustc_middle::{
lint::in_external_macro,
Expand All @@ -27,7 +29,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig);
} else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
check_must_use_candidate(
cx,
Expand All @@ -49,7 +51,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
let attrs = cx.tcx.hir().attrs(item.hir_id());
let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig);
} else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
check_must_use_candidate(
cx,
Expand All @@ -72,7 +74,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
let attrs = cx.tcx.hir().attrs(item.hir_id());
let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig);
} else if let hir::TraitFn::Provided(eid) = *eid {
let body = cx.tcx.hir().body(eid);
if attr.is_none() && is_public && !is_proc_macro(attrs) {
Expand All @@ -97,6 +99,7 @@ fn check_needless_must_use(
item_span: Span,
fn_header_span: Span,
attr: &Attribute,
sig: &FnSig<'_>,
) {
if in_external_macro(cx.sess(), item_span) {
return;
Expand All @@ -112,6 +115,15 @@ fn check_needless_must_use(
},
);
} else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
// Ignore async functions unless Future::Output type is a must_use type
if sig.header.is_async() {
let infcx = cx.tcx.infer_ctxt().build();
if let Some(future_ty) = infcx.get_impl_future_output_ty(return_ty(cx, item_id))
&& !is_must_use_ty(cx, future_ty) {
return;
}
}

span_lint_and_help(
cx,
DOUBLE_MUST_USE,
Expand Down
11 changes: 11 additions & 0 deletions tests/ui/double_must_use.rs
Expand Up @@ -21,6 +21,17 @@ pub fn must_use_with_note() -> Result<(), ()> {
unimplemented!();
}

// vvvv Should not lint (#10486)
#[must_use]
async fn async_must_use() -> usize {
unimplemented!();
}

#[must_use]
async fn async_must_use_result() -> Result<(), ()> {
Ok(())
}

fn main() {
must_use_result();
must_use_tuple();
Expand Down
10 changes: 9 additions & 1 deletion tests/ui/double_must_use.stderr
Expand Up @@ -23,5 +23,13 @@ LL | pub fn must_use_array() -> [Result<(), ()>; 1] {
|
= help: either add some descriptive text or remove the attribute

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

error: aborting due to 4 previous errors

0 comments on commit 85d9f17

Please sign in to comment.