Skip to content

Commit 47a4184

Browse files
authored
Rollup merge of #87065 - FabianWolff:issue-87046, r=oli-obk
Fix ICE with unsized type in const pattern Fixes #87046. The `deref_const()` query currently contains the following check: https://github.com/rust-lang/rust/blob/e9a387d6cf5961a7f2dcb671da3147bd413355c4/compiler/rustc_mir/src/const_eval/mod.rs#L191-L204 i.e. this will cause an ICE for every unsized type except slices. An error is reported with my changes if such a type is used as a const pattern (this should not be a breaking change, since so far, this has caused an ICE).
2 parents fab45bf + 79f0743 commit 47a4184

File tree

3 files changed

+65
-11
lines changed

3 files changed

+65
-11
lines changed

compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

+23-11
Original file line numberDiff line numberDiff line change
@@ -490,17 +490,29 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
490490
// convert the dereferenced constant to a pattern that is the sub-pattern of the
491491
// deref pattern.
492492
_ => {
493-
let old = self.behind_reference.replace(true);
494-
// In case there are structural-match violations somewhere in this subpattern,
495-
// we fall back to a const pattern. If we do not do this, we may end up with
496-
// a !structural-match constant that is not of reference type, which makes it
497-
// very hard to invoke `PartialEq::eq` on it as a fallback.
498-
let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) {
499-
Ok(subpattern) => PatKind::Deref { subpattern },
500-
Err(_) => PatKind::Constant { value: cv },
501-
};
502-
self.behind_reference.set(old);
503-
val
493+
if !pointee_ty.is_sized(tcx.at(span), param_env) {
494+
// `tcx.deref_const()` below will ICE with an unsized type
495+
// (except slices, which are handled in a separate arm above).
496+
let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
497+
if self.include_lint_checks {
498+
tcx.sess.span_err(span, &msg);
499+
} else {
500+
tcx.sess.delay_span_bug(span, &msg);
501+
}
502+
PatKind::Wild
503+
} else {
504+
let old = self.behind_reference.replace(true);
505+
// In case there are structural-match violations somewhere in this subpattern,
506+
// we fall back to a const pattern. If we do not do this, we may end up with
507+
// a !structural-match constant that is not of reference type, which makes it
508+
// very hard to invoke `PartialEq::eq` on it as a fallback.
509+
let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) {
510+
Ok(subpattern) => PatKind::Deref { subpattern },
511+
Err(_) => PatKind::Constant { value: cv },
512+
};
513+
self.behind_reference.set(old);
514+
val
515+
}
504516
}
505517
},
506518
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => {

src/test/ui/consts/issue-87046.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Regression test for the ICE described in #87046.
2+
3+
#![crate_type="lib"]
4+
#![allow(unreachable_patterns)]
5+
#![feature(const_fn_union)]
6+
7+
#[derive(PartialEq, Eq)]
8+
#[repr(transparent)]
9+
pub struct Username(str);
10+
11+
pub const ROOT_USER: &Username = Username::from_str("root");
12+
13+
impl Username {
14+
pub const fn from_str(raw: &str) -> &Self {
15+
union Transmute<'a> {
16+
raw: &'a str,
17+
typed: &'a Username,
18+
}
19+
20+
unsafe { Transmute { raw }.typed }
21+
}
22+
23+
pub const fn as_str(&self) -> &str {
24+
&self.0
25+
}
26+
27+
pub fn is_root(&self) -> bool {
28+
match self {
29+
ROOT_USER => true,
30+
//~^ ERROR: cannot use unsized non-slice type `Username` in constant patterns
31+
_ => false,
32+
}
33+
}
34+
}

src/test/ui/consts/issue-87046.stderr

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: cannot use unsized non-slice type `Username` in constant patterns
2+
--> $DIR/issue-87046.rs:29:13
3+
|
4+
LL | ROOT_USER => true,
5+
| ^^^^^^^^^
6+
7+
error: aborting due to previous error
8+

0 commit comments

Comments
 (0)