1use std::iter;
2
3use rustc_errors::pluralize;
4use rustc_hir::def::{DefKind, Res};
5use rustc_hir::def_id::DefId;
6use rustc_hir::{self as hir, LangItem, find_attr};
7use rustc_infer::traits::util::elaborate;
8use rustc_middle::ty::{self, Ty, Unnormalized};
9use rustc_session::{declare_lint, declare_lint_pass};
10use rustc_span::{Span, Symbol, sym};
11use tracing::instrument;
12
13use crate::lints::{
14 UnusedClosure, UnusedCoroutine, UnusedDef, UnusedDefSuggestion, UnusedOp, UnusedOpSuggestion,
15 UnusedResult,
16};
17use crate::{LateContext, LateLintPass, LintContext};
18
19#[doc =
r" The `unused_must_use` lint detects unused result of a type flagged as"]
#[doc = r" `#[must_use]`."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" fn returns_result() -> Result<(), ()> {"]
#[doc = r" Ok(())"]
#[doc = r" }"]
#[doc = r""]
#[doc = r" fn main() {"]
#[doc = r" returns_result();"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" The `#[must_use]` attribute is an indicator that it is a mistake to"]
#[doc = r" ignore the value. See [the reference] for more details."]
#[doc = r""]
#[doc =
r" [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"]
pub static UNUSED_MUST_USE: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "UNUSED_MUST_USE",
default_level: ::rustc_lint_defs::Warn,
desc: "unused result of a type flagged as `#[must_use]`",
is_externally_loaded: false,
report_in_external_macro: true,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
20 pub UNUSED_MUST_USE,
44 Warn,
45 "unused result of a type flagged as `#[must_use]`",
46 report_in_external_macro
47}
48
49#[doc = r" The `unused_results` lint checks for the unused result of an"]
#[doc = r" expression in a statement."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust,compile_fail"]
#[doc = r" #![deny(unused_results)]"]
#[doc = r" fn foo<T>() -> T { panic!() }"]
#[doc = r""]
#[doc = r" fn main() {"]
#[doc = r" foo::<usize>();"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" Ignoring the return value of a function may indicate a mistake. In"]
#[doc =
r" cases were it is almost certain that the result should be used, it is"]
#[doc =
r" recommended to annotate the function with the [`must_use` attribute]."]
#[doc =
r" Failure to use such a return value will trigger the [`unused_must_use`"]
#[doc = r" lint] which is warn-by-default. The `unused_results` lint is"]
#[doc = r" essentially the same, but triggers for *all* return values."]
#[doc = r""]
#[doc =
r#" This lint is "allow" by default because it can be noisy, and may not be"#]
#[doc =
r" an actual problem. For example, calling the `remove` method of a `Vec`"]
#[doc =
r" or `HashMap` returns the previous value, which you may not care about."]
#[doc =
r" Using this lint would require explicitly ignoring or discarding such"]
#[doc = r" values."]
#[doc = r""]
#[doc =
r" [`must_use` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"]
#[doc = r" [`unused_must_use` lint]: warn-by-default.html#unused-must-use"]
pub static UNUSED_RESULTS: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "UNUSED_RESULTS",
default_level: ::rustc_lint_defs::Allow,
desc: "unused result of an expression in a statement",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
50 pub UNUSED_RESULTS,
84 Allow,
85 "unused result of an expression in a statement"
86}
87
88pub struct UnusedResults;
#[automatically_derived]
impl ::core::marker::Copy for UnusedResults { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for UnusedResults { }
#[automatically_derived]
impl ::core::clone::Clone for UnusedResults {
#[inline]
fn clone(&self) -> UnusedResults { *self }
}
impl ::rustc_lint_defs::LintPass for UnusedResults {
fn name(&self) -> &'static str { "UnusedResults" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[UNUSED_MUST_USE, UNUSED_RESULTS]))
}
}
impl UnusedResults {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[UNUSED_MUST_USE, UNUSED_RESULTS]))
}
}declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]);
89
90#[derive(#[automatically_derived]
impl ::core::fmt::Debug for IsTyMustUse {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
IsTyMustUse::Yes(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Yes",
&__self_0),
IsTyMustUse::No => ::core::fmt::Formatter::write_str(f, "No"),
IsTyMustUse::Trivial =>
::core::fmt::Formatter::write_str(f, "Trivial"),
}
}
}Debug)]
92pub enum IsTyMustUse {
93 Yes(MustUsePath),
96 No,
99 Trivial,
102}
103
104impl IsTyMustUse {
105 fn map(self, f: impl FnOnce(MustUsePath) -> MustUsePath) -> Self {
106 match self {
107 Self::Yes(must_use_path) => Self::Yes(f(must_use_path)),
108 _ => self,
109 }
110 }
111}
112
113#[derive(#[automatically_derived]
impl ::core::fmt::Debug for MustUsePath {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
MustUsePath::Def(__self_0, __self_1, __self_2) =>
::core::fmt::Formatter::debug_tuple_field3_finish(f, "Def",
__self_0, __self_1, &__self_2),
MustUsePath::Boxed(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Boxed",
&__self_0),
MustUsePath::Pinned(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Pinned",
&__self_0),
MustUsePath::Opaque(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Opaque",
&__self_0),
MustUsePath::TraitObject(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"TraitObject", &__self_0),
MustUsePath::TupleElement(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"TupleElement", &__self_0),
MustUsePath::Result(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Result",
&__self_0),
MustUsePath::ControlFlow(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ControlFlow", &__self_0),
MustUsePath::Array(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f, "Array",
__self_0, &__self_1),
MustUsePath::Closure(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Closure", &__self_0),
MustUsePath::Coroutine(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Coroutine", &__self_0),
}
}
}Debug)]
115pub enum MustUsePath {
116 Def(Span, DefId, Option<Symbol>),
118 Boxed(Box<Self>),
119 Pinned(Box<Self>),
120 Opaque(Box<Self>),
121 TraitObject(Box<Self>),
122 TupleElement(Vec<(usize, Self)>),
123 Result(Box<Self>),
125 ControlFlow(Box<Self>),
127 Array(Box<Self>, u64),
128 Closure(Span),
130 Coroutine(Span),
132}
133
134x;#[instrument(skip(cx, expr), level = "debug", ret)]
143pub fn is_ty_must_use<'tcx>(
144 cx: &LateContext<'tcx>,
145 ty: Ty<'tcx>,
146 expr: &hir::Expr<'_>,
147 simplify_uninhabited: bool,
148) -> IsTyMustUse {
149 if ty.is_unit() {
150 return IsTyMustUse::Trivial;
151 }
152
153 let parent_mod_did = cx.tcx.parent_module(expr.hir_id).to_def_id();
154 let is_uninhabited =
155 |t: Ty<'tcx>| !t.is_inhabited_from(cx.tcx, parent_mod_did, cx.typing_env());
156
157 match *ty.kind() {
158 _ if is_uninhabited(ty) => IsTyMustUse::Trivial,
159 ty::Adt(..) if let Some(boxed) = ty.boxed_ty() => {
160 is_ty_must_use(cx, boxed, expr, simplify_uninhabited)
161 .map(|inner| MustUsePath::Boxed(Box::new(inner)))
162 }
163 ty::Adt(def, args) if cx.tcx.is_lang_item(def.did(), LangItem::Pin) => {
164 let pinned_ty = args.type_at(0);
165 is_ty_must_use(cx, pinned_ty, expr, simplify_uninhabited)
166 .map(|inner| MustUsePath::Pinned(Box::new(inner)))
167 }
168 ty::Adt(def, args)
170 if simplify_uninhabited
171 && cx.tcx.is_diagnostic_item(sym::Result, def.did())
172 && is_uninhabited(args.type_at(1)) =>
173 {
174 let ok_ty = args.type_at(0);
175 is_ty_must_use(cx, ok_ty, expr, simplify_uninhabited)
176 .map(|path| MustUsePath::Result(Box::new(path)))
177 }
178 ty::Adt(def, args)
180 if simplify_uninhabited
181 && cx.tcx.is_diagnostic_item(sym::ControlFlow, def.did())
182 && is_uninhabited(args.type_at(0)) =>
183 {
184 let continue_ty = args.type_at(1);
185 is_ty_must_use(cx, continue_ty, expr, simplify_uninhabited)
186 .map(|path| MustUsePath::ControlFlow(Box::new(path)))
187 }
188 ty::Adt(def, args)
190 if cx.tcx.is_diagnostic_item(sym::Result, def.did())
191 && args.type_at(0).is_unit()
192 && is_uninhabited(args.type_at(1)) =>
193 {
194 IsTyMustUse::Trivial
195 }
196 ty::Adt(def, args)
198 if cx.tcx.is_diagnostic_item(sym::ControlFlow, def.did())
199 && args.type_at(1).is_unit()
200 && is_uninhabited(args.type_at(0)) =>
201 {
202 IsTyMustUse::Trivial
203 }
204 ty::Adt(def, _) => {
205 is_def_must_use(cx, def.did(), expr.span).map_or(IsTyMustUse::No, IsTyMustUse::Yes)
206 }
207 ty::Alias(ty::AliasTy {
208 kind: ty::Opaque { def_id: def } | ty::Projection { def_id: def },
209 ..
210 }) => {
211 elaborate(
212 cx.tcx,
213 cx.tcx
214 .explicit_item_self_bounds(def)
215 .iter_identity_copied()
216 .map(Unnormalized::skip_norm_wip),
217 )
218 .filter_only_self()
220 .find_map(|(pred, _span)| {
221 if let ty::ClauseKind::Trait(ref poly_trait_predicate) = pred.kind().skip_binder() {
223 let def_id = poly_trait_predicate.trait_ref.def_id;
224
225 is_def_must_use(cx, def_id, expr.span)
226 } else {
227 None
228 }
229 })
230 .map(|inner| MustUsePath::Opaque(Box::new(inner)))
231 .map_or(IsTyMustUse::No, IsTyMustUse::Yes)
232 }
233 ty::Dynamic(binders, _) => binders
234 .iter()
235 .find_map(|predicate| {
236 if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
237 let def_id = trait_ref.def_id;
238 is_def_must_use(cx, def_id, expr.span)
239 .map(|inner| MustUsePath::TraitObject(Box::new(inner)))
240 } else {
241 None
242 }
243 })
244 .map_or(IsTyMustUse::No, IsTyMustUse::Yes),
245 ty::Tuple(tys) => {
247 let elem_exprs = if let hir::ExprKind::Tup(elem_exprs) = expr.kind {
248 debug_assert_eq!(elem_exprs.len(), tys.len());
249 elem_exprs
250 } else {
251 &[]
252 };
253
254 let elem_exprs = elem_exprs.iter().chain(iter::repeat(expr));
256
257 let mut all_trivial = true;
258 let mut nested_must_use = Vec::new();
259
260 tys.iter().zip(elem_exprs).enumerate().for_each(|(i, (ty, expr))| {
261 let must_use = is_ty_must_use(cx, ty, expr, simplify_uninhabited);
262
263 all_trivial &= matches!(must_use, IsTyMustUse::Trivial);
264 if let IsTyMustUse::Yes(path) = must_use {
265 nested_must_use.push((i, path));
266 }
267 });
268
269 if all_trivial {
270 IsTyMustUse::Trivial
273 } else if !nested_must_use.is_empty() {
274 IsTyMustUse::Yes(MustUsePath::TupleElement(nested_must_use))
275 } else {
276 IsTyMustUse::No
277 }
278 }
279 ty::Array(ty, len) => match len.try_to_target_usize(cx.tcx) {
280 Some(0) | None => IsTyMustUse::No,
282 Some(len) => is_ty_must_use(cx, ty, expr, simplify_uninhabited)
284 .map(|inner| MustUsePath::Array(Box::new(inner), len)),
285 },
286 ty::Closure(..) | ty::CoroutineClosure(..) => {
287 IsTyMustUse::Yes(MustUsePath::Closure(expr.span))
288 }
289 ty::Coroutine(def_id, ..) => {
290 if cx.tcx.coroutine_is_async(def_id)
292 && let Some(def_id) = cx.tcx.lang_items().future_trait()
293 {
294 IsTyMustUse::Yes(MustUsePath::Opaque(Box::new(
295 is_def_must_use(cx, def_id, expr.span)
296 .expect("future trait is marked as `#[must_use]`"),
297 )))
298 } else {
299 IsTyMustUse::Yes(MustUsePath::Coroutine(expr.span))
300 }
301 }
302 _ => IsTyMustUse::No,
303 }
304}
305
306impl<'tcx> LateLintPass<'tcx> for UnusedResults {
307 fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
308 let hir::StmtKind::Semi(mut expr) = s.kind else {
309 return;
310 };
311
312 let mut expr_is_from_block = false;
313 while let hir::ExprKind::Block(blk, ..) = expr.kind
314 && let hir::Block { expr: Some(e), .. } = blk
315 {
316 expr = e;
317 expr_is_from_block = true;
318 }
319
320 if let hir::ExprKind::Ret(..) = expr.kind {
321 return;
322 }
323
324 if let hir::ExprKind::Match(await_expr, _arms, hir::MatchSource::AwaitDesugar) = expr.kind
325 && let ty = cx.typeck_results().expr_ty(await_expr)
326 && let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: future_def_id }, .. }) = ty.kind()
327 && cx.tcx.ty_is_opaque_future(ty)
328 && let async_fn_def_id = cx.tcx.parent(*future_def_id)
329 && #[allow(non_exhaustive_omitted_patterns)] match cx.tcx.def_kind(async_fn_def_id)
{
DefKind::Fn | DefKind::AssocFn => true,
_ => false,
}matches!(cx.tcx.def_kind(async_fn_def_id), DefKind::Fn | DefKind::AssocFn)
330 && cx.tcx.asyncness(async_fn_def_id).is_async()
332 && check_must_use_def(
333 cx,
334 async_fn_def_id,
335 expr.span,
336 "output of future returned by ",
337 "",
338 expr_is_from_block,
339 )
340 {
341 return;
344 }
345
346 let ty = cx.typeck_results().expr_ty(expr);
347
348 let must_use_result = is_ty_must_use(cx, ty, expr, false);
349 let type_lint_emitted_or_trivial = match must_use_result {
350 IsTyMustUse::Yes(path) => {
351 emit_must_use_untranslated(cx, &path, "", "", 1, false, expr_is_from_block);
352 true
353 }
354 IsTyMustUse::Trivial => true,
355 IsTyMustUse::No => false,
356 };
357
358 let fn_warned = check_fn_must_use(cx, expr, expr_is_from_block);
359
360 if !fn_warned && type_lint_emitted_or_trivial {
361 return;
364 }
365
366 let must_use_op = match expr.kind {
367 hir::ExprKind::Binary(bin_op, ..) => match bin_op.node {
371 hir::BinOpKind::Eq
372 | hir::BinOpKind::Lt
373 | hir::BinOpKind::Le
374 | hir::BinOpKind::Ne
375 | hir::BinOpKind::Ge
376 | hir::BinOpKind::Gt => Some("comparison"),
377 hir::BinOpKind::Add
378 | hir::BinOpKind::Sub
379 | hir::BinOpKind::Div
380 | hir::BinOpKind::Mul
381 | hir::BinOpKind::Rem => Some("arithmetic operation"),
382 hir::BinOpKind::And | hir::BinOpKind::Or => Some("logical operation"),
383 hir::BinOpKind::BitXor
384 | hir::BinOpKind::BitAnd
385 | hir::BinOpKind::BitOr
386 | hir::BinOpKind::Shl
387 | hir::BinOpKind::Shr => Some("bitwise operation"),
388 },
389 hir::ExprKind::AddrOf(..) => Some("borrow"),
390 hir::ExprKind::OffsetOf(..) => Some("`offset_of` call"),
391 hir::ExprKind::Unary(..) => Some("unary operation"),
392 hir::ExprKind::ConstBlock(block) => {
394 let body = cx.tcx.hir_body(block.body);
395 if let hir::ExprKind::Block(block, _) = body.value.kind
396 && let Some(expr) = block.expr
397 && let hir::ExprKind::OffsetOf(..) = expr.kind
398 {
399 Some("`offset_of` call")
400 } else {
401 None
402 }
403 }
404 _ => None,
405 };
406
407 let op_warned = match must_use_op {
408 Some(must_use_op) => {
409 let span = expr.span.find_ancestor_not_from_macro().unwrap_or(expr.span);
410 cx.emit_span_lint(
411 UNUSED_MUST_USE,
412 expr.span,
413 UnusedOp {
414 op: must_use_op,
415 label: expr.span,
416 suggestion: if expr_is_from_block {
417 UnusedOpSuggestion::BlockTailExpr {
418 before_span: span.shrink_to_lo(),
419 after_span: span.shrink_to_hi(),
420 }
421 } else {
422 UnusedOpSuggestion::NormalExpr { span: span.shrink_to_lo() }
423 },
424 },
425 );
426 true
427 }
428 None => false,
429 };
430
431 if !(type_lint_emitted_or_trivial || fn_warned || op_warned) {
433 cx.emit_span_lint(UNUSED_RESULTS, s.span, UnusedResult { ty });
434 }
435 }
436}
437
438fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expr_is_from_block: bool) -> bool {
441 let maybe_def_id = match expr.kind {
442 hir::ExprKind::Call(callee, _) => {
443 if let hir::ExprKind::Path(ref qpath) = callee.kind
444 && let Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) =
447 cx.qpath_res(qpath, callee.hir_id)
448 {
449 Some(def_id)
450 } else {
451 None
452 }
453 }
454 hir::ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
455 _ => None,
456 };
457
458 match maybe_def_id {
459 Some(def_id) => {
460 check_must_use_def(cx, def_id, expr.span, "return value of ", "", expr_is_from_block)
461 }
462 None => false,
463 }
464}
465
466fn is_def_must_use(cx: &LateContext<'_>, def_id: DefId, span: Span) -> Option<MustUsePath> {
467 {
{
'done:
{
for i in ::rustc_hir::attrs::HasAttrs::get_attrs(def_id, &cx.tcx)
{
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(MustUse { reason, .. }) => {
break 'done Some(reason);
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}find_attr!(cx.tcx, def_id, MustUse { reason, .. } => reason)
469 .map(|reason| MustUsePath::Def(span, def_id, *reason))
470}
471
472fn check_must_use_def(
474 cx: &LateContext<'_>,
475 def_id: DefId,
476 span: Span,
477 descr_pre_path: &str,
478 descr_post_path: &str,
479 expr_is_from_block: bool,
480) -> bool {
481 is_def_must_use(cx, def_id, span)
482 .map(|must_use_path| {
483 emit_must_use_untranslated(
484 cx,
485 &must_use_path,
486 descr_pre_path,
487 descr_post_path,
488 1,
489 false,
490 expr_is_from_block,
491 )
492 })
493 .is_some()
494}
495
496#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("emit_must_use_untranslated",
"rustc_lint::unused::must_use", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/unused/must_use.rs"),
::tracing_core::__macro_support::Option::Some(496u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::unused::must_use"),
::tracing_core::field::FieldSet::new(&["path", "descr_pre",
"descr_post", "plural_len", "is_inner",
"expr_is_from_block"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&path)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&descr_pre as
&dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&descr_post as
&dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&plural_len as
&dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&is_inner as
&dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&expr_is_from_block
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
let plural_suffix = if plural_len == 1 { "" } else { "s" };
match path {
MustUsePath::Boxed(path) => {
let descr_pre =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}boxed ", descr_pre))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len, true, expr_is_from_block);
}
MustUsePath::Pinned(path) => {
let descr_pre =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}pinned ", descr_pre))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len, true, expr_is_from_block);
}
MustUsePath::Opaque(path) => {
let descr_pre =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}implementer{1} of ",
descr_pre, plural_suffix))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len, true, expr_is_from_block);
}
MustUsePath::TraitObject(path) => {
let descr_post =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" trait object{0}{1}",
plural_suffix, descr_post))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len, true, expr_is_from_block);
}
MustUsePath::TupleElement(elems) => {
for (index, path) in elems {
let descr_post =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" in tuple element {0}",
index))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len, true, expr_is_from_block);
}
}
MustUsePath::Result(path) => {
let descr_post =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" in a `Result` with an uninhabited error{0}",
descr_post))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len, true, expr_is_from_block);
}
MustUsePath::ControlFlow(path) => {
let descr_post =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" in a `ControlFlow` with an uninhabited break {0}",
descr_post))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len, true, expr_is_from_block);
}
MustUsePath::Array(path, len) => {
let descr_pre =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}array{1} of ",
descr_pre, plural_suffix))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)),
true, expr_is_from_block);
}
MustUsePath::Closure(span) => {
cx.emit_span_lint(UNUSED_MUST_USE, *span,
UnusedClosure {
count: plural_len,
pre: descr_pre,
post: descr_post,
});
}
MustUsePath::Coroutine(span) => {
cx.emit_span_lint(UNUSED_MUST_USE, *span,
UnusedCoroutine {
count: plural_len,
pre: descr_pre,
post: descr_post,
});
}
MustUsePath::Def(span, def_id, reason) => {
let ancenstor_span =
span.find_ancestor_not_from_macro().unwrap_or(*span);
let is_redundant_let_ignore =
cx.sess().source_map().span_to_prev_source(ancenstor_span).ok().map(|prev|
prev.trim_end().ends_with("let _ =")).unwrap_or(false);
let suggestion_span =
if is_redundant_let_ignore {
*span
} else { ancenstor_span };
cx.emit_span_lint(UNUSED_MUST_USE, ancenstor_span,
UnusedDef {
pre: descr_pre,
post: descr_post,
cx,
def_id: *def_id,
note: *reason,
suggestion: (!is_inner).then_some(if expr_is_from_block {
UnusedDefSuggestion::BlockTailExpr {
before_span: suggestion_span.shrink_to_lo(),
after_span: suggestion_span.shrink_to_hi(),
}
} else {
UnusedDefSuggestion::NormalExpr {
span: suggestion_span.shrink_to_lo(),
}
}),
});
}
}
}
}
}#[instrument(skip(cx), level = "debug")]
497fn emit_must_use_untranslated(
498 cx: &LateContext<'_>,
499 path: &MustUsePath,
500 descr_pre: &str,
501 descr_post: &str,
502 plural_len: usize,
503 is_inner: bool,
504 expr_is_from_block: bool,
505) {
506 let plural_suffix = pluralize!(plural_len);
507
508 match path {
509 MustUsePath::Boxed(path) => {
510 let descr_pre = &format!("{descr_pre}boxed ");
511 emit_must_use_untranslated(
512 cx,
513 path,
514 descr_pre,
515 descr_post,
516 plural_len,
517 true,
518 expr_is_from_block,
519 );
520 }
521 MustUsePath::Pinned(path) => {
522 let descr_pre = &format!("{descr_pre}pinned ");
523 emit_must_use_untranslated(
524 cx,
525 path,
526 descr_pre,
527 descr_post,
528 plural_len,
529 true,
530 expr_is_from_block,
531 );
532 }
533 MustUsePath::Opaque(path) => {
534 let descr_pre = &format!("{descr_pre}implementer{plural_suffix} of ");
535 emit_must_use_untranslated(
536 cx,
537 path,
538 descr_pre,
539 descr_post,
540 plural_len,
541 true,
542 expr_is_from_block,
543 );
544 }
545 MustUsePath::TraitObject(path) => {
546 let descr_post = &format!(" trait object{plural_suffix}{descr_post}");
547 emit_must_use_untranslated(
548 cx,
549 path,
550 descr_pre,
551 descr_post,
552 plural_len,
553 true,
554 expr_is_from_block,
555 );
556 }
557 MustUsePath::TupleElement(elems) => {
558 for (index, path) in elems {
559 let descr_post = &format!(" in tuple element {index}");
560 emit_must_use_untranslated(
561 cx,
562 path,
563 descr_pre,
564 descr_post,
565 plural_len,
566 true,
567 expr_is_from_block,
568 );
569 }
570 }
571 MustUsePath::Result(path) => {
572 let descr_post = &format!(" in a `Result` with an uninhabited error{descr_post}");
573 emit_must_use_untranslated(
574 cx,
575 path,
576 descr_pre,
577 descr_post,
578 plural_len,
579 true,
580 expr_is_from_block,
581 );
582 }
583 MustUsePath::ControlFlow(path) => {
584 let descr_post = &format!(" in a `ControlFlow` with an uninhabited break {descr_post}");
585 emit_must_use_untranslated(
586 cx,
587 path,
588 descr_pre,
589 descr_post,
590 plural_len,
591 true,
592 expr_is_from_block,
593 );
594 }
595 MustUsePath::Array(path, len) => {
596 let descr_pre = &format!("{descr_pre}array{plural_suffix} of ");
597 emit_must_use_untranslated(
598 cx,
599 path,
600 descr_pre,
601 descr_post,
602 plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)),
603 true,
604 expr_is_from_block,
605 );
606 }
607 MustUsePath::Closure(span) => {
608 cx.emit_span_lint(
609 UNUSED_MUST_USE,
610 *span,
611 UnusedClosure { count: plural_len, pre: descr_pre, post: descr_post },
612 );
613 }
614 MustUsePath::Coroutine(span) => {
615 cx.emit_span_lint(
616 UNUSED_MUST_USE,
617 *span,
618 UnusedCoroutine { count: plural_len, pre: descr_pre, post: descr_post },
619 );
620 }
621 MustUsePath::Def(span, def_id, reason) => {
622 let ancenstor_span = span.find_ancestor_not_from_macro().unwrap_or(*span);
623 let is_redundant_let_ignore = cx
624 .sess()
625 .source_map()
626 .span_to_prev_source(ancenstor_span)
627 .ok()
628 .map(|prev| prev.trim_end().ends_with("let _ ="))
629 .unwrap_or(false);
630 let suggestion_span = if is_redundant_let_ignore { *span } else { ancenstor_span };
631 cx.emit_span_lint(
632 UNUSED_MUST_USE,
633 ancenstor_span,
634 UnusedDef {
635 pre: descr_pre,
636 post: descr_post,
637 cx,
638 def_id: *def_id,
639 note: *reason,
640 suggestion: (!is_inner).then_some(if expr_is_from_block {
641 UnusedDefSuggestion::BlockTailExpr {
642 before_span: suggestion_span.shrink_to_lo(),
643 after_span: suggestion_span.shrink_to_hi(),
644 }
645 } else {
646 UnusedDefSuggestion::NormalExpr { span: suggestion_span.shrink_to_lo() }
647 }),
648 },
649 );
650 }
651 }
652}