Skip to content

Commit d233522

Browse files
Rollup merge of #112529 - jieyouxu:block-expr-unused-must-use, r=oli-obk
Extend `unused_must_use` to cover block exprs Given code like ```rust #[must_use] fn foo() -> i32 { 42 } fn warns() { { foo(); } } fn does_not_warn() { { foo() }; } fn main() { warns(); does_not_warn(); } ``` ### Before This PR ``` warning: unused return value of `foo` that must be used --> test.rs:8:9 | 8 | foo(); | ^^^^^ | = note: `#[warn(unused_must_use)]` on by default help: use `let _ = ...` to ignore the resulting value | 8 | let _ = foo(); | +++++++ warning: 1 warning emitted ``` ### After This PR ``` warning: unused return value of `foo` that must be used --> test.rs:8:9 | 8 | foo(); | ^^^^^ | = note: `#[warn(unused_must_use)]` on by default help: use `let _ = ...` to ignore the resulting value | 8 | let _ = foo(); | +++++++ warning: unused return value of `foo` that must be used --> test.rs:14:9 | 14 | foo() | ^^^^^ | help: use `let _ = ...` to ignore the resulting value | 14 | let _ = foo(); | +++++++ + warning: 2 warnings emitted ``` Fixes #104253.
2 parents db7d837 + 72b3b58 commit d233522

19 files changed

+289
-65
lines changed

compiler/rustc_arena/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ struct ArenaChunk<T = u8> {
6767

6868
unsafe impl<#[may_dangle] T> Drop for ArenaChunk<T> {
6969
fn drop(&mut self) {
70-
unsafe { Box::from_raw(self.storage.as_mut()) };
70+
unsafe { drop(Box::from_raw(self.storage.as_mut())) }
7171
}
7272
}
7373

compiler/rustc_lint/src/lints.rs

+42-11
Original file line numberDiff line numberDiff line change
@@ -1555,8 +1555,29 @@ pub struct UnusedOp<'a> {
15551555
pub op: &'a str,
15561556
#[label]
15571557
pub label: Span,
1558-
#[suggestion(style = "verbose", code = "let _ = ", applicability = "maybe-incorrect")]
1559-
pub suggestion: Span,
1558+
#[subdiagnostic]
1559+
pub suggestion: UnusedOpSuggestion,
1560+
}
1561+
1562+
#[derive(Subdiagnostic)]
1563+
pub enum UnusedOpSuggestion {
1564+
#[suggestion(
1565+
lint_suggestion,
1566+
style = "verbose",
1567+
code = "let _ = ",
1568+
applicability = "maybe-incorrect"
1569+
)]
1570+
NormalExpr {
1571+
#[primary_span]
1572+
span: Span,
1573+
},
1574+
#[multipart_suggestion(lint_suggestion, style = "verbose", applicability = "maybe-incorrect")]
1575+
BlockTailExpr {
1576+
#[suggestion_part(code = "let _ = ")]
1577+
before_span: Span,
1578+
#[suggestion_part(code = ";")]
1579+
after_span: Span,
1580+
},
15601581
}
15611582

15621583
#[derive(LintDiagnostic)]
@@ -1599,15 +1620,25 @@ pub struct UnusedDef<'a, 'b> {
15991620
}
16001621

16011622
#[derive(Subdiagnostic)]
1602-
#[suggestion(
1603-
lint_suggestion,
1604-
style = "verbose",
1605-
code = "let _ = ",
1606-
applicability = "maybe-incorrect"
1607-
)]
1608-
pub struct UnusedDefSuggestion {
1609-
#[primary_span]
1610-
pub span: Span,
1623+
1624+
pub enum UnusedDefSuggestion {
1625+
#[suggestion(
1626+
lint_suggestion,
1627+
style = "verbose",
1628+
code = "let _ = ",
1629+
applicability = "maybe-incorrect"
1630+
)]
1631+
NormalExpr {
1632+
#[primary_span]
1633+
span: Span,
1634+
},
1635+
#[multipart_suggestion(lint_suggestion, style = "verbose", applicability = "maybe-incorrect")]
1636+
BlockTailExpr {
1637+
#[suggestion_part(code = "let _ = ")]
1638+
before_span: Span,
1639+
#[suggestion_part(code = ";")]
1640+
after_span: Span,
1641+
},
16111642
}
16121643

16131644
// Needed because of def_path_str

compiler/rustc_lint/src/unused.rs

+81-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::lints::{
22
PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag,
33
UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDefSuggestion, UnusedDelim,
4-
UnusedDelimSuggestion, UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedResult,
4+
UnusedDelimSuggestion, UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedOpSuggestion,
5+
UnusedResult,
56
};
67
use crate::Lint;
78
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
@@ -93,7 +94,15 @@ declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]);
9394

9495
impl<'tcx> LateLintPass<'tcx> for UnusedResults {
9596
fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
96-
let hir::StmtKind::Semi(expr) = s.kind else { return; };
97+
let hir::StmtKind::Semi(mut expr) = s.kind else { return; };
98+
99+
let mut expr_is_from_block = false;
100+
while let hir::ExprKind::Block(blk, ..) = expr.kind
101+
&& let hir::Block { expr: Some(e), .. } = blk
102+
{
103+
expr = e;
104+
expr_is_from_block = true;
105+
}
97106

98107
if let hir::ExprKind::Ret(..) = expr.kind {
99108
return;
@@ -113,6 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
113122
expr.span,
114123
"output of future returned by ",
115124
"",
125+
expr_is_from_block,
116126
)
117127
{
118128
// We have a bare `foo().await;` on an opaque type from an async function that was
@@ -125,13 +135,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
125135
let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span);
126136
let type_lint_emitted_or_suppressed = match must_use_result {
127137
Some(path) => {
128-
emit_must_use_untranslated(cx, &path, "", "", 1, false);
138+
emit_must_use_untranslated(cx, &path, "", "", 1, false, expr_is_from_block);
129139
true
130140
}
131141
None => false,
132142
};
133143

134-
let fn_warned = check_fn_must_use(cx, expr);
144+
let fn_warned = check_fn_must_use(cx, expr, expr_is_from_block);
135145

136146
if !fn_warned && type_lint_emitted_or_suppressed {
137147
// We don't warn about unused unit or uninhabited types.
@@ -176,7 +186,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
176186
UnusedOp {
177187
op: must_use_op,
178188
label: expr.span,
179-
suggestion: expr.span.shrink_to_lo(),
189+
suggestion: if expr_is_from_block {
190+
UnusedOpSuggestion::BlockTailExpr {
191+
before_span: expr.span.shrink_to_lo(),
192+
after_span: expr.span.shrink_to_hi(),
193+
}
194+
} else {
195+
UnusedOpSuggestion::NormalExpr { span: expr.span.shrink_to_lo() }
196+
},
180197
},
181198
);
182199
op_warned = true;
@@ -186,7 +203,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
186203
cx.emit_spanned_lint(UNUSED_RESULTS, s.span, UnusedResult { ty });
187204
}
188205

189-
fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
206+
fn check_fn_must_use(
207+
cx: &LateContext<'_>,
208+
expr: &hir::Expr<'_>,
209+
expr_is_from_block: bool,
210+
) -> bool {
190211
let maybe_def_id = match expr.kind {
191212
hir::ExprKind::Call(ref callee, _) => {
192213
match callee.kind {
@@ -207,7 +228,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
207228
_ => None,
208229
};
209230
if let Some(def_id) = maybe_def_id {
210-
check_must_use_def(cx, def_id, expr.span, "return value of ", "")
231+
check_must_use_def(
232+
cx,
233+
def_id,
234+
expr.span,
235+
"return value of ",
236+
"",
237+
expr_is_from_block,
238+
)
211239
} else {
212240
false
213241
}
@@ -350,6 +378,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
350378
span: Span,
351379
descr_pre_path: &str,
352380
descr_post_path: &str,
381+
expr_is_from_block: bool,
353382
) -> bool {
354383
is_def_must_use(cx, def_id, span)
355384
.map(|must_use_path| {
@@ -360,6 +389,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
360389
descr_post_path,
361390
1,
362391
false,
392+
expr_is_from_block,
363393
)
364394
})
365395
.is_some()
@@ -373,28 +403,59 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
373403
descr_post: &str,
374404
plural_len: usize,
375405
is_inner: bool,
406+
expr_is_from_block: bool,
376407
) {
377408
let plural_suffix = pluralize!(plural_len);
378409

379410
match path {
380411
MustUsePath::Suppressed => {}
381412
MustUsePath::Boxed(path) => {
382413
let descr_pre = &format!("{}boxed ", descr_pre);
383-
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true);
414+
emit_must_use_untranslated(
415+
cx,
416+
path,
417+
descr_pre,
418+
descr_post,
419+
plural_len,
420+
true,
421+
expr_is_from_block,
422+
);
384423
}
385424
MustUsePath::Opaque(path) => {
386425
let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix);
387-
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true);
426+
emit_must_use_untranslated(
427+
cx,
428+
path,
429+
descr_pre,
430+
descr_post,
431+
plural_len,
432+
true,
433+
expr_is_from_block,
434+
);
388435
}
389436
MustUsePath::TraitObject(path) => {
390437
let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post);
391-
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true);
438+
emit_must_use_untranslated(
439+
cx,
440+
path,
441+
descr_pre,
442+
descr_post,
443+
plural_len,
444+
true,
445+
expr_is_from_block,
446+
);
392447
}
393448
MustUsePath::TupleElement(elems) => {
394449
for (index, path) in elems {
395450
let descr_post = &format!(" in tuple element {}", index);
396451
emit_must_use_untranslated(
397-
cx, path, descr_pre, descr_post, plural_len, true,
452+
cx,
453+
path,
454+
descr_pre,
455+
descr_post,
456+
plural_len,
457+
true,
458+
expr_is_from_block,
398459
);
399460
}
400461
}
@@ -407,6 +468,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
407468
descr_post,
408469
plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)),
409470
true,
471+
expr_is_from_block,
410472
);
411473
}
412474
MustUsePath::Closure(span) => {
@@ -433,8 +495,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
433495
cx,
434496
def_id: *def_id,
435497
note: *reason,
436-
suggestion: (!is_inner)
437-
.then_some(UnusedDefSuggestion { span: span.shrink_to_lo() }),
498+
suggestion: (!is_inner).then_some(if expr_is_from_block {
499+
UnusedDefSuggestion::BlockTailExpr {
500+
before_span: span.shrink_to_lo(),
501+
after_span: span.shrink_to_hi(),
502+
}
503+
} else {
504+
UnusedDefSuggestion::NormalExpr { span: span.shrink_to_lo() }
505+
}),
438506
},
439507
);
440508
}

library/core/src/primitive_docs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ mod prim_never {}
308308
///
309309
/// ```no_run
310310
/// // Undefined behaviour
311-
/// unsafe { char::from_u32_unchecked(0x110000) };
311+
/// let _ = unsafe { char::from_u32_unchecked(0x110000) };
312312
/// ```
313313
///
314314
/// USVs are also the exact set of values that may be encoded in UTF-8. Because

library/core/tests/ptr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1001,7 +1001,7 @@ fn nonnull_tagged_pointer_with_provenance() {
10011001
assert_eq!(p.tag(), 3);
10021002
assert_eq!(unsafe { *p.pointer().as_ptr() }, 10);
10031003

1004-
unsafe { Box::from_raw(p.pointer().as_ptr()) };
1004+
unsafe { drop(Box::from_raw(p.pointer().as_ptr())) };
10051005

10061006
/// A non-null pointer type which carries several bits of metadata and maintains provenance.
10071007
#[repr(transparent)]

library/std/src/primitive_docs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ mod prim_never {}
308308
///
309309
/// ```no_run
310310
/// // Undefined behaviour
311-
/// unsafe { char::from_u32_unchecked(0x110000) };
311+
/// let _ = unsafe { char::from_u32_unchecked(0x110000) };
312312
/// ```
313313
///
314314
/// USVs are also the exact set of values that may be encoded in UTF-8. Because

src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#![warn(clippy::transmute_ptr_to_ref)]
44
#![allow(clippy::match_single_binding)]
5+
#![allow(unused_must_use)]
56

67
unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
78
let _: &T = &*p;
@@ -38,7 +39,7 @@ fn _issue1231() {
3839

3940
type Bar<'a> = &'a u8;
4041
let raw = 42 as *const i32;
41-
unsafe { &*(raw as *const u8) };
42+
let _ = unsafe { &*(raw as *const u8) };
4243
}
4344

4445
unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {

src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#![warn(clippy::transmute_ptr_to_ref)]
44
#![allow(clippy::match_single_binding)]
5+
#![allow(unused_must_use)]
56

67
unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
78
let _: &T = std::mem::transmute(p);
@@ -38,7 +39,7 @@ fn _issue1231() {
3839

3940
type Bar<'a> = &'a u8;
4041
let raw = 42 as *const i32;
41-
unsafe { std::mem::transmute::<_, Bar>(raw) };
42+
let _ = unsafe { std::mem::transmute::<_, Bar>(raw) };
4243
}
4344

4445
unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {

0 commit comments

Comments
 (0)