about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-09-05 07:53:49 -0400
committerMichael Goulet <michael@errs.io>2024-10-05 18:36:47 -0400
commit515b93297ff6b96e6368070f3eb3f3a833112bc0 (patch)
tree054ed4eea67bcc6f3f82d512ca696b3fc36fe4d4
parent73d49f8c697da34ee1372b51540bfb0f1ae0c712 (diff)
Document things a bit more carefully, also account for coercion in check_expr_has_type_or_error
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs16
-rw-r--r--tests/mir-opt/uninhabited_not_read.rs1
-rw-r--r--tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr6
4 files changed, 18 insertions, 6 deletions
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 1705421c2f4..96bff04dbc7 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -186,6 +186,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             if self.coerce_never {
                 return success(simple(Adjust::NeverToAny)(b), b, vec![]);
             } else {
+                // Otherwise the only coercion we can do is unification.
                 return self.unify_and(a, b, identity);
             }
         }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 870a260c9fe..604bec95701 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -62,7 +62,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // While we don't allow *arbitrary* coercions here, we *do* allow
         // coercions from ! to `expected`.
-        if ty.is_never() {
+        if ty.is_never() && self.expr_constitutes_read(expr) {
             if let Some(_) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {
                 let reported = self.dcx().span_delayed_bug(
                     expr.span,
@@ -260,6 +260,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty
     }
 
+    /// Whether this expression constitutes a read of value of the type that
+    /// it evaluates to.
+    ///
+    /// This is used to determine if we should consider the block to diverge
+    /// if the expression evaluates to `!`, and if we should insert a `NeverToAny`
+    /// coercion for values of type `!`.
+    ///
+    /// This function generally returns `false` if the expression is a place
+    /// expression and the *parent* expression is the scrutinee of a match or
+    /// the pointee of an `&` addr-of expression, since both of those parent
+    /// expressions take a *place* and not a value.
+    ///
+    /// This function is unfortunately a bit heuristical, though it is certainly
+    /// far sounder than the prior status quo: <https://github.com/rust-lang/rust/issues/117288>.
     pub(super) fn expr_constitutes_read(&self, expr: &'tcx hir::Expr<'tcx>) -> bool {
         // We only care about place exprs. Anything else returns an immediate
         // which would constitute a read. We don't care about distinguishing
diff --git a/tests/mir-opt/uninhabited_not_read.rs b/tests/mir-opt/uninhabited_not_read.rs
index 39ffdbdbb33..15769cdd75b 100644
--- a/tests/mir-opt/uninhabited_not_read.rs
+++ b/tests/mir-opt/uninhabited_not_read.rs
@@ -24,4 +24,3 @@ fn main() {
         let _ = *x;
     }
 }
-
diff --git a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
index f8ed792e3c6..e0d900a1eb5 100644
--- a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
+++ b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
@@ -7,14 +7,12 @@ LL |     let c1 = || match x { };
    |                       ^ `x` used here but it isn't initialized
 
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/pattern-matching-should-fail.rs:15:14
+  --> $DIR/pattern-matching-should-fail.rs:15:23
    |
 LL |     let x: !;
    |         - binding declared here but left uninitialized
 LL |     let c2 = || match x { _ => () };
-   |              ^^       - borrow occurs due to use in closure
-   |              |
-   |              `x` used here but it isn't initialized
+   |                       ^ `x` used here but it isn't initialized
 
 error[E0381]: used binding `variant` isn't initialized
   --> $DIR/pattern-matching-should-fail.rs:27:13