Skip to content

Commit 35d95f3

Browse files
committed
Use #[must_use] determination from the compiler
1 parent 4883595 commit 35d95f3

File tree

5 files changed

+19
-50
lines changed

5 files changed

+19
-50
lines changed

clippy_lints/src/drop_forget_ref.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
102102
sym::mem_drop
103103
if !(arg_ty.needs_drop(cx.tcx, cx.typing_env())
104104
|| is_must_use_func_call(cx, arg)
105-
|| is_must_use_ty(cx, arg_ty)
105+
|| is_must_use_ty(cx, arg_ty, expr.hir_id)
106106
|| drop_is_single_call_in_arm) =>
107107
{
108108
(DROP_NON_DROP, DROP_NON_DROP_SUMMARY.into(), Some(arg.span))

clippy_lints/src/functions/must_use.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
4141
cx,
4242
sig.decl,
4343
item.owner_id,
44+
item.hir_id(),
4445
item.span,
4546
fn_header_span,
4647
*attr_span,
@@ -74,6 +75,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
7475
cx,
7576
sig.decl,
7677
item.owner_id,
78+
item.hir_id(),
7779
item.span,
7880
fn_header_span,
7981
*attr_span,
@@ -108,6 +110,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
108110
cx,
109111
sig.decl,
110112
item.owner_id,
113+
item.hir_id(),
111114
item.span,
112115
fn_header_span,
113116
*attr_span,
@@ -138,6 +141,7 @@ fn check_needless_must_use(
138141
cx: &LateContext<'_>,
139142
decl: &hir::FnDecl<'_>,
140143
item_id: hir::OwnerId,
144+
item_hir_id: hir::HirId,
141145
item_span: Span,
142146
fn_header_span: Span,
143147
attr_span: Span,
@@ -174,12 +178,12 @@ fn check_needless_must_use(
174178
"remove `must_use`",
175179
);
176180
}
177-
} else if reason.is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
181+
} else if reason.is_none() && is_must_use_ty(cx, return_ty(cx, item_id), item_hir_id) {
178182
// Ignore async functions unless Future::Output type is a must_use type
179183
if sig.header.is_async() {
180184
let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
181185
if let Some(future_ty) = infcx.err_ctxt().get_impl_future_output_ty(return_ty(cx, item_id))
182-
&& !is_must_use_ty(cx, future_ty)
186+
&& !is_must_use_ty(cx, future_ty, item_hir_id)
183187
{
184188
return;
185189
}
@@ -210,7 +214,7 @@ fn check_must_use_candidate<'tcx>(
210214
|| item_span.in_external_macro(cx.sess().source_map())
211215
|| returns_unit(decl)
212216
|| !cx.effective_visibilities.is_exported(item_id.def_id)
213-
|| is_must_use_ty(cx, return_ty(cx, item_id))
217+
|| is_must_use_ty(cx, return_ty(cx, item_id), body.value.hir_id)
214218
|| item_span.from_expansion()
215219
|| is_entrypoint_fn(cx, item_id.def_id.to_def_id())
216220
{

clippy_lints/src/let_underscore.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
170170
diag.help("consider awaiting the future or dropping explicitly with `std::mem::drop`");
171171
},
172172
);
173-
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
173+
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init), init.hir_id) {
174174
#[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
175175
span_lint_and_then(
176176
cx,

clippy_lints/src/return_self_not_must_use.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa
8888
// there is one, we shouldn't emit a warning!
8989
&& self_arg.peel_refs() == ret_ty
9090
// If `Self` is already marked as `#[must_use]`, no need for the attribute here.
91-
&& !is_must_use_ty(cx, ret_ty)
91+
&& !is_must_use_ty(cx, ret_ty, cx.tcx.local_def_id_to_hir_id(fn_def))
9292
{
9393
span_lint_and_help(
9494
cx,

clippy_utils/src/ty/mod.rs

Lines changed: 9 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ use rustc_hir as hir;
1010
use rustc_hir::attrs::AttributeKind;
1111
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
1212
use rustc_hir::def_id::DefId;
13-
use rustc_hir::{Expr, FnDecl, LangItem, find_attr};
13+
use rustc_hir::{Expr, ExprKind, FnDecl, HirId, LangItem};
1414
use rustc_hir_analysis::lower_ty;
1515
use rustc_infer::infer::TyCtxtInferExt;
1616
use rustc_lint::LateContext;
17+
use rustc_lint::unused::must_use::{IsTyMustUse, is_ty_must_use};
1718
use rustc_middle::mir::ConstValue;
1819
use rustc_middle::mir::interpret::Scalar;
1920
use rustc_middle::traits::EvaluationResult;
@@ -310,49 +311,13 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
310311
// Returns whether the `ty` has `#[must_use]` attribute. If `ty` is a `Result`/`ControlFlow`
311312
// whose `Err`/`Break` payload is an uninhabited type, the `Ok`/`Continue` payload type
312313
// will be used instead. See <https://github.com/rust-lang/rust/pull/148214>.
313-
pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
314-
match ty.kind() {
315-
ty::Adt(adt, args) => match cx.tcx.get_diagnostic_name(adt.did()) {
316-
Some(sym::Result) if args.type_at(1).is_privately_uninhabited(cx.tcx, cx.typing_env()) => {
317-
is_must_use_ty(cx, args.type_at(0))
318-
},
319-
Some(sym::ControlFlow) if args.type_at(0).is_privately_uninhabited(cx.tcx, cx.typing_env()) => {
320-
is_must_use_ty(cx, args.type_at(1))
321-
},
322-
_ => find_attr!(cx.tcx.get_all_attrs(adt.did()), AttributeKind::MustUse { .. }),
323-
},
324-
ty::Foreign(did) => find_attr!(cx.tcx.get_all_attrs(*did), AttributeKind::MustUse { .. }),
325-
ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => {
326-
// for the Array case we don't need to care for the len == 0 case
327-
// because we don't want to lint functions returning empty arrays
328-
is_must_use_ty(cx, *ty)
329-
},
330-
ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)),
331-
ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => {
332-
for (predicate, _) in cx.tcx.explicit_item_self_bounds(def_id).skip_binder() {
333-
if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
334-
&& find_attr!(
335-
cx.tcx.get_all_attrs(trait_predicate.trait_ref.def_id),
336-
AttributeKind::MustUse { .. }
337-
)
338-
{
339-
return true;
340-
}
341-
}
342-
false
343-
},
344-
ty::Dynamic(binder, _) => {
345-
for predicate in *binder {
346-
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
347-
&& find_attr!(cx.tcx.get_all_attrs(trait_ref.def_id), AttributeKind::MustUse { .. })
348-
{
349-
return true;
350-
}
351-
}
352-
false
353-
},
354-
_ => false,
355-
}
314+
pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, hir_id: HirId) -> bool {
315+
let dummy_expr = Expr {
316+
hir_id,
317+
span: DUMMY_SP,
318+
kind: ExprKind::Ret(None),
319+
};
320+
matches!(is_ty_must_use(cx, ty, &dummy_expr, true), IsTyMustUse::Yes(_))
356321
}
357322

358323
/// Returns `true` if the given type is a non aggregate primitive (a `bool` or `char`, any

0 commit comments

Comments
 (0)