Extend unused_must_use to cover block exprs

This commit is contained in:
许杰友 Jieyou Xu (Joe) 2023-06-11 23:44:28 +08:00
parent 314c39d2ea
commit 72b3b58efc
No known key found for this signature in database
GPG Key ID: C5FD5D32014FDB47
19 changed files with 289 additions and 65 deletions

View File

@ -67,7 +67,7 @@ struct ArenaChunk<T = u8> {
unsafe impl<#[may_dangle] T> Drop for ArenaChunk<T> {
fn drop(&mut self) {
unsafe { Box::from_raw(self.storage.as_mut()) };
unsafe { drop(Box::from_raw(self.storage.as_mut())) }
}
}

View File

@ -1534,8 +1534,29 @@ pub struct UnusedOp<'a> {
pub op: &'a str,
#[label]
pub label: Span,
#[suggestion(style = "verbose", code = "let _ = ", applicability = "maybe-incorrect")]
pub suggestion: Span,
#[subdiagnostic]
pub suggestion: UnusedOpSuggestion,
}
#[derive(Subdiagnostic)]
pub enum UnusedOpSuggestion {
#[suggestion(
lint_suggestion,
style = "verbose",
code = "let _ = ",
applicability = "maybe-incorrect"
)]
NormalExpr {
#[primary_span]
span: Span,
},
#[multipart_suggestion(lint_suggestion, style = "verbose", applicability = "maybe-incorrect")]
BlockTailExpr {
#[suggestion_part(code = "let _ = ")]
before_span: Span,
#[suggestion_part(code = ";")]
after_span: Span,
},
}
#[derive(LintDiagnostic)]
@ -1578,15 +1599,25 @@ pub struct UnusedDef<'a, 'b> {
}
#[derive(Subdiagnostic)]
#[suggestion(
lint_suggestion,
style = "verbose",
code = "let _ = ",
applicability = "maybe-incorrect"
)]
pub struct UnusedDefSuggestion {
#[primary_span]
pub span: Span,
pub enum UnusedDefSuggestion {
#[suggestion(
lint_suggestion,
style = "verbose",
code = "let _ = ",
applicability = "maybe-incorrect"
)]
NormalExpr {
#[primary_span]
span: Span,
},
#[multipart_suggestion(lint_suggestion, style = "verbose", applicability = "maybe-incorrect")]
BlockTailExpr {
#[suggestion_part(code = "let _ = ")]
before_span: Span,
#[suggestion_part(code = ";")]
after_span: Span,
},
}
// Needed because of def_path_str

View File

@ -1,7 +1,8 @@
use crate::lints::{
PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag,
UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDefSuggestion, UnusedDelim,
UnusedDelimSuggestion, UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedResult,
UnusedDelimSuggestion, UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedOpSuggestion,
UnusedResult,
};
use crate::Lint;
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
@ -93,7 +94,15 @@ declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]);
impl<'tcx> LateLintPass<'tcx> for UnusedResults {
fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
let hir::StmtKind::Semi(expr) = s.kind else { return; };
let hir::StmtKind::Semi(mut expr) = s.kind else { return; };
let mut expr_is_from_block = false;
while let hir::ExprKind::Block(blk, ..) = expr.kind
&& let hir::Block { expr: Some(e), .. } = blk
{
expr = e;
expr_is_from_block = true;
}
if let hir::ExprKind::Ret(..) = expr.kind {
return;
@ -113,6 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
expr.span,
"output of future returned by ",
"",
expr_is_from_block,
)
{
// 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 {
let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span);
let type_lint_emitted_or_suppressed = match must_use_result {
Some(path) => {
emit_must_use_untranslated(cx, &path, "", "", 1, false);
emit_must_use_untranslated(cx, &path, "", "", 1, false, expr_is_from_block);
true
}
None => false,
};
let fn_warned = check_fn_must_use(cx, expr);
let fn_warned = check_fn_must_use(cx, expr, expr_is_from_block);
if !fn_warned && type_lint_emitted_or_suppressed {
// We don't warn about unused unit or uninhabited types.
@ -176,7 +186,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
UnusedOp {
op: must_use_op,
label: expr.span,
suggestion: expr.span.shrink_to_lo(),
suggestion: if expr_is_from_block {
UnusedOpSuggestion::BlockTailExpr {
before_span: expr.span.shrink_to_lo(),
after_span: expr.span.shrink_to_hi(),
}
} else {
UnusedOpSuggestion::NormalExpr { span: expr.span.shrink_to_lo() }
},
},
);
op_warned = true;
@ -186,7 +203,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
cx.emit_spanned_lint(UNUSED_RESULTS, s.span, UnusedResult { ty });
}
fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
fn check_fn_must_use(
cx: &LateContext<'_>,
expr: &hir::Expr<'_>,
expr_is_from_block: bool,
) -> bool {
let maybe_def_id = match expr.kind {
hir::ExprKind::Call(ref callee, _) => {
match callee.kind {
@ -207,7 +228,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
_ => None,
};
if let Some(def_id) = maybe_def_id {
check_must_use_def(cx, def_id, expr.span, "return value of ", "")
check_must_use_def(
cx,
def_id,
expr.span,
"return value of ",
"",
expr_is_from_block,
)
} else {
false
}
@ -350,6 +378,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
span: Span,
descr_pre_path: &str,
descr_post_path: &str,
expr_is_from_block: bool,
) -> bool {
is_def_must_use(cx, def_id, span)
.map(|must_use_path| {
@ -360,6 +389,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_post_path,
1,
false,
expr_is_from_block,
)
})
.is_some()
@ -373,6 +403,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_post: &str,
plural_len: usize,
is_inner: bool,
expr_is_from_block: bool,
) {
let plural_suffix = pluralize!(plural_len);
@ -380,21 +411,51 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
MustUsePath::Suppressed => {}
MustUsePath::Boxed(path) => {
let descr_pre = &format!("{}boxed ", descr_pre);
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true);
emit_must_use_untranslated(
cx,
path,
descr_pre,
descr_post,
plural_len,
true,
expr_is_from_block,
);
}
MustUsePath::Opaque(path) => {
let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix);
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true);
emit_must_use_untranslated(
cx,
path,
descr_pre,
descr_post,
plural_len,
true,
expr_is_from_block,
);
}
MustUsePath::TraitObject(path) => {
let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post);
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true);
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 = &format!(" in tuple element {}", index);
emit_must_use_untranslated(
cx, path, descr_pre, descr_post, plural_len, true,
cx,
path,
descr_pre,
descr_post,
plural_len,
true,
expr_is_from_block,
);
}
}
@ -407,6 +468,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_post,
plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)),
true,
expr_is_from_block,
);
}
MustUsePath::Closure(span) => {
@ -433,8 +495,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
cx,
def_id: *def_id,
note: *reason,
suggestion: (!is_inner)
.then_some(UnusedDefSuggestion { span: span.shrink_to_lo() }),
suggestion: (!is_inner).then_some(if expr_is_from_block {
UnusedDefSuggestion::BlockTailExpr {
before_span: span.shrink_to_lo(),
after_span: span.shrink_to_hi(),
}
} else {
UnusedDefSuggestion::NormalExpr { span: span.shrink_to_lo() }
}),
},
);
}

View File

@ -308,7 +308,7 @@ mod prim_never {}
///
/// ```no_run
/// // Undefined behaviour
/// unsafe { char::from_u32_unchecked(0x110000) };
/// let _ = unsafe { char::from_u32_unchecked(0x110000) };
/// ```
///
/// USVs are also the exact set of values that may be encoded in UTF-8. Because

View File

@ -1001,7 +1001,7 @@ fn nonnull_tagged_pointer_with_provenance() {
assert_eq!(p.tag(), 3);
assert_eq!(unsafe { *p.pointer().as_ptr() }, 10);
unsafe { Box::from_raw(p.pointer().as_ptr()) };
unsafe { drop(Box::from_raw(p.pointer().as_ptr())) };
/// A non-null pointer type which carries several bits of metadata and maintains provenance.
#[repr(transparent)]

View File

@ -308,7 +308,7 @@ mod prim_never {}
///
/// ```no_run
/// // Undefined behaviour
/// unsafe { char::from_u32_unchecked(0x110000) };
/// let _ = unsafe { char::from_u32_unchecked(0x110000) };
/// ```
///
/// USVs are also the exact set of values that may be encoded in UTF-8. Because

View File

@ -2,6 +2,7 @@
#![warn(clippy::transmute_ptr_to_ref)]
#![allow(clippy::match_single_binding)]
#![allow(unused_must_use)]
unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
let _: &T = &*p;
@ -38,7 +39,7 @@ fn _issue1231() {
type Bar<'a> = &'a u8;
let raw = 42 as *const i32;
unsafe { &*(raw as *const u8) };
let _ = unsafe { &*(raw as *const u8) };
}
unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {

View File

@ -2,6 +2,7 @@
#![warn(clippy::transmute_ptr_to_ref)]
#![allow(clippy::match_single_binding)]
#![allow(unused_must_use)]
unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
let _: &T = std::mem::transmute(p);
@ -38,7 +39,7 @@ fn _issue1231() {
type Bar<'a> = &'a u8;
let raw = 42 as *const i32;
unsafe { std::mem::transmute::<_, Bar>(raw) };
let _ = unsafe { std::mem::transmute::<_, Bar>(raw) };
}
unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {

View File

@ -1,5 +1,5 @@
error: transmute from a pointer type (`*const T`) to a reference type (`&T`)
--> $DIR/transmute_ptr_to_ref.rs:7:17
--> $DIR/transmute_ptr_to_ref.rs:8:17
|
LL | let _: &T = std::mem::transmute(p);
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p`
@ -7,127 +7,127 @@ LL | let _: &T = std::mem::transmute(p);
= note: `-D clippy::transmute-ptr-to-ref` implied by `-D warnings`
error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
--> $DIR/transmute_ptr_to_ref.rs:10:21
--> $DIR/transmute_ptr_to_ref.rs:11:21
|
LL | let _: &mut T = std::mem::transmute(m);
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m`
error: transmute from a pointer type (`*mut T`) to a reference type (`&T`)
--> $DIR/transmute_ptr_to_ref.rs:13:17
--> $DIR/transmute_ptr_to_ref.rs:14:17
|
LL | let _: &T = std::mem::transmute(m);
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m`
error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
--> $DIR/transmute_ptr_to_ref.rs:16:21
--> $DIR/transmute_ptr_to_ref.rs:17:21
|
LL | let _: &mut T = std::mem::transmute(p as *mut T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)`
error: transmute from a pointer type (`*const U`) to a reference type (`&T`)
--> $DIR/transmute_ptr_to_ref.rs:19:17
--> $DIR/transmute_ptr_to_ref.rs:20:17
|
LL | let _: &T = std::mem::transmute(o);
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)`
error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`)
--> $DIR/transmute_ptr_to_ref.rs:22:21
--> $DIR/transmute_ptr_to_ref.rs:23:21
|
LL | let _: &mut T = std::mem::transmute(om);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)`
error: transmute from a pointer type (`*mut U`) to a reference type (`&T`)
--> $DIR/transmute_ptr_to_ref.rs:25:17
--> $DIR/transmute_ptr_to_ref.rs:26:17
|
LL | let _: &T = std::mem::transmute(om);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)`
error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`)
--> $DIR/transmute_ptr_to_ref.rs:35:32
--> $DIR/transmute_ptr_to_ref.rs:36:32
|
LL | let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<_>>()`
error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`)
--> $DIR/transmute_ptr_to_ref.rs:37:33
--> $DIR/transmute_ptr_to_ref.rs:38:33
|
LL | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<&_>>()`
error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`)
--> $DIR/transmute_ptr_to_ref.rs:41:14
--> $DIR/transmute_ptr_to_ref.rs:42:22
|
LL | unsafe { std::mem::transmute::<_, Bar>(raw) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)`
LL | let _ = unsafe { std::mem::transmute::<_, Bar>(raw) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
--> $DIR/transmute_ptr_to_ref.rs:46:14
--> $DIR/transmute_ptr_to_ref.rs:47:14
|
LL | 0 => std::mem::transmute(x),
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
--> $DIR/transmute_ptr_to_ref.rs:47:14
--> $DIR/transmute_ptr_to_ref.rs:48:14
|
LL | 1 => std::mem::transmute(y),
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
--> $DIR/transmute_ptr_to_ref.rs:48:14
--> $DIR/transmute_ptr_to_ref.rs:49:14
|
LL | 2 => std::mem::transmute::<_, &&'b u32>(x),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
--> $DIR/transmute_ptr_to_ref.rs:49:14
--> $DIR/transmute_ptr_to_ref.rs:50:14
|
LL | _ => std::mem::transmute::<_, &&'b u32>(y),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()`
error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
--> $DIR/transmute_ptr_to_ref.rs:57:19
--> $DIR/transmute_ptr_to_ref.rs:58:19
|
LL | let _: &u32 = std::mem::transmute(a);
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a`
error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
--> $DIR/transmute_ptr_to_ref.rs:58:19
--> $DIR/transmute_ptr_to_ref.rs:59:19
|
LL | let _: &u32 = std::mem::transmute::<_, &u32>(a);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::<u32>()`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
--> $DIR/transmute_ptr_to_ref.rs:60:14
--> $DIR/transmute_ptr_to_ref.rs:61:14
|
LL | 0 => std::mem::transmute(x),
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
--> $DIR/transmute_ptr_to_ref.rs:61:14
--> $DIR/transmute_ptr_to_ref.rs:62:14
|
LL | _ => std::mem::transmute::<_, &&'b u32>(x),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()`
error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
--> $DIR/transmute_ptr_to_ref.rs:69:19
--> $DIR/transmute_ptr_to_ref.rs:70:19
|
LL | let _: &u32 = std::mem::transmute(a);
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a`
error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
--> $DIR/transmute_ptr_to_ref.rs:70:19
--> $DIR/transmute_ptr_to_ref.rs:71:19
|
LL | let _: &u32 = std::mem::transmute::<_, &u32>(a);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
--> $DIR/transmute_ptr_to_ref.rs:72:14
--> $DIR/transmute_ptr_to_ref.rs:73:14
|
LL | 0 => std::mem::transmute(x),
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
--> $DIR/transmute_ptr_to_ref.rs:73:14
--> $DIR/transmute_ptr_to_ref.rs:74:14
|
LL | _ => std::mem::transmute::<_, &&'b u32>(x),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)`

View File

@ -10,7 +10,7 @@ fn fill(v: &mut i32) {
}
fn evil() {
unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR: is a dangling pointer
let _ = unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR: is a dangling pointer
}
fn main() {

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance)
--> $DIR/storage_dead_dangling.rs:LL:CC
|
LL | unsafe { &mut *(LEAK as *mut i32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance)
LL | let _ = unsafe { &mut *(LEAK as *mut i32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -2,6 +2,6 @@
#[allow(deprecated, invalid_value)]
fn main() {
unsafe { std::mem::uninitialized::<!>() };
let _ = unsafe { std::mem::uninitialized::<!>() };
//~^ ERROR: attempted to instantiate uninhabited type `!`
}

View File

@ -1,8 +1,8 @@
error: abnormal termination: aborted execution: attempted to instantiate uninhabited type `!`
--> $DIR/uninit_uninhabited_type.rs:LL:CC
|
LL | unsafe { std::mem::uninitialized::<!>() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
LL | let _ = unsafe { std::mem::uninitialized::<!>() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
|
= note: inside `main` at $DIR/uninit_uninhabited_type.rs:LL:CC

View File

@ -1,5 +1,5 @@
#[allow(deprecated, invalid_value)]
fn main() {
unsafe { std::mem::zeroed::<fn()>() };
let _ = unsafe { std::mem::zeroed::<fn()>() };
//~^ ERROR: attempted to zero-initialize type `fn()`, which is invalid
}

View File

@ -1,8 +1,8 @@
error: abnormal termination: aborted execution: attempted to zero-initialize type `fn()`, which is invalid
--> $DIR/zero_fn_ptr.rs:LL:CC
|
LL | unsafe { std::mem::zeroed::<fn()>() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `fn()`, which is invalid
LL | let _ = unsafe { std::mem::zeroed::<fn()>() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `fn()`, which is invalid
|
= note: inside `main` at $DIR/zero_fn_ptr.rs:LL:CC

View File

@ -1,8 +1,8 @@
warning: unused closure that must be used
--> $DIR/issue-1460.rs:6:5
--> $DIR/issue-1460.rs:6:6
|
LL | {|i: u32| if 1 == i { }};
| ^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: closures are lazy and do nothing unless called
= note: `#[warn(unused_must_use)]` on by default

View File

@ -0,0 +1,36 @@
// run-rustfix
// check-pass
#![warn(unused_must_use)]
#[must_use]
fn foo() -> i32 {
42
}
fn bar() {
{
let _ = foo();
//~^ WARN unused return value
}
}
fn baz() {
{
let _ = foo();
//~^ WARN unused return value
};
}
fn main() {
bar();
baz();
{
let _ = 1 + 2;
//~^ WARN unused arithmetic operation
}
{
let _ = 1 + 2;
//~^ WARN unused arithmetic operation
};
}

View File

@ -0,0 +1,36 @@
// run-rustfix
// check-pass
#![warn(unused_must_use)]
#[must_use]
fn foo() -> i32 {
42
}
fn bar() {
{
foo();
//~^ WARN unused return value
}
}
fn baz() {
{
foo()
//~^ WARN unused return value
};
}
fn main() {
bar();
baz();
{
1 + 2;
//~^ WARN unused arithmetic operation
}
{
1 + 2
//~^ WARN unused arithmetic operation
};
}

View File

@ -0,0 +1,51 @@
warning: unused return value of `foo` that must be used
--> $DIR/must-use-block-expr.rs:13:9
|
LL | foo();
| ^^^^^
|
note: the lint level is defined here
--> $DIR/must-use-block-expr.rs:4:9
|
LL | #![warn(unused_must_use)]
| ^^^^^^^^^^^^^^^
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo();
| +++++++
warning: unused return value of `foo` that must be used
--> $DIR/must-use-block-expr.rs:20:9
|
LL | foo()
| ^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo();
| +++++++ +
warning: unused arithmetic operation that must be used
--> $DIR/must-use-block-expr.rs:29:9
|
LL | 1 + 2;
| ^^^^^ the arithmetic operation produces a value
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = 1 + 2;
| +++++++
warning: unused arithmetic operation that must be used
--> $DIR/must-use-block-expr.rs:33:9
|
LL | 1 + 2
| ^^^^^ the arithmetic operation produces a value
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = 1 + 2;
| +++++++ +
warning: 4 warnings emitted