about summary refs log tree commit diff
diff options
context:
space:
mode:
author许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com>2023-06-11 23:44:28 +0800
committer许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com>2023-06-15 17:59:13 +0800
commit72b3b58efc6ed4bab93ba98586b62750abbdda79 (patch)
treee69ee17e3d202a7a150e4e95c16c9bff6fe637bd
parent314c39d2ea07d8b50649149358ebeb1a6bd09179 (diff)
downloadrust-72b3b58efc6ed4bab93ba98586b62750abbdda79.tar.gz
rust-72b3b58efc6ed4bab93ba98586b62750abbdda79.zip
Extend `unused_must_use` to cover block exprs
-rw-r--r--compiler/rustc_arena/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/lints.rs53
-rw-r--r--compiler/rustc_lint/src/unused.rs94
-rw-r--r--library/core/src/primitive_docs.rs2
-rw-r--r--library/core/tests/ptr.rs2
-rw-r--r--library/std/src/primitive_docs.rs2
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed3
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs3
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr48
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr4
-rw-r--r--tests/ui/issues/issue-1460.stderr4
-rw-r--r--tests/ui/lint/unused/must-use-block-expr.fixed36
-rw-r--r--tests/ui/lint/unused/must-use-block-expr.rs36
-rw-r--r--tests/ui/lint/unused/must-use-block-expr.stderr51
19 files changed, 289 insertions, 65 deletions
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 6e15f06a76d..ba47ebd68cb 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -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())) }
     }
 }
 
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index e990c771bdf..9bcf672672a 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -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
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 04df23c736b..9861610612f 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -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() }
+                            }),
                         },
                     );
                 }
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 8266e899011..80289ca08c3 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -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
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index c02cd99cc44..ee885adfeee 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -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)]
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index 8266e899011..80289ca08c3 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -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
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
index 575dadde906..ac55ab5a8e2 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
@@ -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 {
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
index 4238ff80478..901a3e90dbe 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
@@ -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 {
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
index b3e6c09d2d7..68007edc410 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
@@ -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)`
diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs
index 03113585d14..366930a831c 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs
@@ -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() {
diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr
index 2ba8116cadc..6c41add60ef 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr
@@ -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
diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs
index e606d8b283c..59781f02366 100644
--- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs
+++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs
@@ -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 `!`
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr
index 150128ba2a4..f2cc3430326 100644
--- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr
@@ -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
 
diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs
index 6d9ae14c5c4..e9c6e464e88 100644
--- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs
+++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs
@@ -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
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr
index 9d44ba9f746..77d58228043 100644
--- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr
@@ -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
 
diff --git a/tests/ui/issues/issue-1460.stderr b/tests/ui/issues/issue-1460.stderr
index eb7661fad56..d4a8c8955e2 100644
--- a/tests/ui/issues/issue-1460.stderr
+++ b/tests/ui/issues/issue-1460.stderr
@@ -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
diff --git a/tests/ui/lint/unused/must-use-block-expr.fixed b/tests/ui/lint/unused/must-use-block-expr.fixed
new file mode 100644
index 00000000000..642012812bd
--- /dev/null
+++ b/tests/ui/lint/unused/must-use-block-expr.fixed
@@ -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
+    };
+}
diff --git a/tests/ui/lint/unused/must-use-block-expr.rs b/tests/ui/lint/unused/must-use-block-expr.rs
new file mode 100644
index 00000000000..e0a680aa07d
--- /dev/null
+++ b/tests/ui/lint/unused/must-use-block-expr.rs
@@ -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
+    };
+}
diff --git a/tests/ui/lint/unused/must-use-block-expr.stderr b/tests/ui/lint/unused/must-use-block-expr.stderr
new file mode 100644
index 00000000000..d821beb1d92
--- /dev/null
+++ b/tests/ui/lint/unused/must-use-block-expr.stderr
@@ -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
+