From 79f0743b6f3e94551e5c7cef209abc042d5cea3b Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Sun, 11 Jul 2021 19:16:26 +0200 Subject: [PATCH] Fix ICE with unsized type in const pattern --- .../src/thir/pattern/const_to_pat.rs | 34 +++++++++++++------ src/test/ui/consts/issue-87046.rs | 34 +++++++++++++++++++ src/test/ui/consts/issue-87046.stderr | 8 +++++ 3 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/consts/issue-87046.rs create mode 100644 src/test/ui/consts/issue-87046.stderr 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 cb9c89324d6b3..3859b22223c00 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 0000000000000..1f147439f8bc3 --- /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 0000000000000..5da7a9e239000 --- /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 +