From 02e95c9f82e0f9ca2d5347533f207eb9bae8053c Mon Sep 17 00:00:00 2001
From: Nadrieril <nadrieril+git@gmail.com>
Date: Thu, 18 Jan 2024 18:22:08 +0100
Subject: [PATCH] Never pattern in `let` statement diverges

---
 compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs   |  6 ++++++
 .../diverge-causes-unreachable-code.rs            | 15 ++++++++-------
 .../diverge-causes-unreachable-code.stderr        | 15 +++++++++++++--
 tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs | 12 ++++++------
 4 files changed, 33 insertions(+), 15 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 4704d52abfc2f..52c5e2752b941 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1473,6 +1473,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Type check a `let` statement.
     pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
         self.check_decl(local.into());
+        if local.pat.is_never_pattern() {
+            self.diverges.set(Diverges::Always {
+                span: local.pat.span,
+                custom_note: Some("any code following a never pattern is unreachable"),
+            });
+        }
     }
 
     pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) {
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs
index 5c852c8adcccf..f7e4007b920d9 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs
@@ -17,13 +17,14 @@ fn ref_never_arg(&!: &Void) -> u32 {
     //~^ ERROR unreachable statement
 }
 
-//fn never_let() -> u32 {
-//    let ptr: *const Void = std::ptr::null();
-//    unsafe {
-//        let ! = *ptr;
-//    }
-//    println!();
-//}
+fn never_let() -> u32 {
+    let ptr: *const Void = std::ptr::null();
+    unsafe {
+        let ! = *ptr;
+    }
+    println!();
+    //~^ ERROR unreachable statement
+}
 
 fn never_match() -> u32 {
     let ptr: *const Void = std::ptr::null();
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr
index c9cd3f53944e4..c33a5855d5068 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr
@@ -24,7 +24,18 @@ LL |     println!();
    = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unreachable statement
-  --> $DIR/diverge-causes-unreachable-code.rs:33:5
+  --> $DIR/diverge-causes-unreachable-code.rs:25:5
+   |
+LL |         let ! = *ptr;
+   |             - any code following a never pattern is unreachable
+LL |     }
+LL |     println!();
+   |     ^^^^^^^^^^ unreachable statement
+   |
+   = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unreachable statement
+  --> $DIR/diverge-causes-unreachable-code.rs:34:5
    |
 LL |         match *ptr { ! };
    |         ---------------- any code following this `match` expression is unreachable, as all arms diverge
@@ -34,5 +45,5 @@ LL |     println!();
    |
    = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs
index 40aa2bd29e594..6f4b81b9b25b0 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs
@@ -13,12 +13,12 @@ fn never_arg(!: Void) -> u32 {}
 
 fn ref_never_arg(&!: &Void) -> u32 {}
 
-// fn never_let() -> u32 {
-//     let ptr: *const Void = std::ptr::null();
-//     unsafe {
-//         let ! = *ptr;
-//     }
-// }
+fn never_let() -> u32 {
+    let ptr: *const Void = std::ptr::null();
+    unsafe {
+        let ! = *ptr;
+    }
+}
 
 fn never_match() -> u32 {
     let ptr: *const Void = std::ptr::null();