about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFabian Wolff <fabian.wolff@alumni.ethz.ch>2021-07-11 19:16:26 +0200
committerFabian Wolff <fabian.wolff@alumni.ethz.ch>2021-07-11 19:16:26 +0200
commit79f0743b6f3e94551e5c7cef209abc042d5cea3b (patch)
tree3ec752957c2546b2b6cd6c873bfc72748254819f
parent81053b912fab51978f4806cddfc37eb9a9a5afc6 (diff)
downloadrust-79f0743b6f3e94551e5c7cef209abc042d5cea3b.tar.gz
rust-79f0743b6f3e94551e5c7cef209abc042d5cea3b.zip
Fix ICE with unsized type in const pattern
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs34
-rw-r--r--src/test/ui/consts/issue-87046.rs34
-rw-r--r--src/test/ui/consts/issue-87046.stderr8
3 files changed, 65 insertions, 11 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index cb9c89324d6..3859b22223c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -490,17 +490,29 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                 // convert the dereferenced constant to a pattern that is the sub-pattern of the
                 // deref pattern.
                 _ => {
-                    let old = self.behind_reference.replace(true);
-                    // In case there are structural-match violations somewhere in this subpattern,
-                    // we fall back to a const pattern. If we do not do this, we may end up with
-                    // a !structural-match constant that is not of reference type, which makes it
-                    // very hard to invoke `PartialEq::eq` on it as a fallback.
-                    let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) {
-                        Ok(subpattern) => PatKind::Deref { subpattern },
-                        Err(_) => PatKind::Constant { value: cv },
-                    };
-                    self.behind_reference.set(old);
-                    val
+                    if !pointee_ty.is_sized(tcx.at(span), param_env) {
+                        // `tcx.deref_const()` below will ICE with an unsized type
+                        // (except slices, which are handled in a separate arm above).
+                        let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
+                        if self.include_lint_checks {
+                            tcx.sess.span_err(span, &msg);
+                        } else {
+                            tcx.sess.delay_span_bug(span, &msg);
+                        }
+                        PatKind::Wild
+                    } else {
+                        let old = self.behind_reference.replace(true);
+                        // In case there are structural-match violations somewhere in this subpattern,
+                        // we fall back to a const pattern. If we do not do this, we may end up with
+                        // a !structural-match constant that is not of reference type, which makes it
+                        // very hard to invoke `PartialEq::eq` on it as a fallback.
+                        let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) {
+                            Ok(subpattern) => PatKind::Deref { subpattern },
+                            Err(_) => PatKind::Constant { value: cv },
+                        };
+                        self.behind_reference.set(old);
+                        val
+                    }
                 }
             },
             ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => {
diff --git a/src/test/ui/consts/issue-87046.rs b/src/test/ui/consts/issue-87046.rs
new file mode 100644
index 00000000000..1f147439f8b
--- /dev/null
+++ b/src/test/ui/consts/issue-87046.rs
@@ -0,0 +1,34 @@
+// Regression test for the ICE described in #87046.
+
+#![crate_type="lib"]
+#![allow(unreachable_patterns)]
+#![feature(const_fn_union)]
+
+#[derive(PartialEq, Eq)]
+#[repr(transparent)]
+pub struct Username(str);
+
+pub const ROOT_USER: &Username = Username::from_str("root");
+
+impl Username {
+    pub const fn from_str(raw: &str) -> &Self {
+        union Transmute<'a> {
+            raw: &'a str,
+            typed: &'a Username,
+        }
+
+        unsafe { Transmute { raw }.typed }
+    }
+
+    pub const fn as_str(&self) -> &str {
+        &self.0
+    }
+
+    pub fn is_root(&self) -> bool {
+        match self {
+            ROOT_USER => true,
+            //~^ ERROR: cannot use unsized non-slice type `Username` in constant patterns
+            _ => false,
+        }
+    }
+}
diff --git a/src/test/ui/consts/issue-87046.stderr b/src/test/ui/consts/issue-87046.stderr
new file mode 100644
index 00000000000..5da7a9e2390
--- /dev/null
+++ b/src/test/ui/consts/issue-87046.stderr
@@ -0,0 +1,8 @@
+error: cannot use unsized non-slice type `Username` in constant patterns
+  --> $DIR/issue-87046.rs:29:13
+   |
+LL |             ROOT_USER => true,
+   |             ^^^^^^^^^
+
+error: aborting due to previous error
+