Skip to content

Commit

Permalink
Rollup merge of #87065 - FabianWolff:issue-87046, r=oli-obk
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
JohnTitor committed Jul 12, 2021
2 parents fab45bf + 79f0743 commit 47a4184
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 11 deletions.
34 changes: 23 additions & 11 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..) => {
Expand Down
34 changes: 34 additions & 0 deletions src/test/ui/consts/issue-87046.rs
Original file line number Diff line number Diff line change
@@ -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,
}
}
}
8 changes: 8 additions & 0 deletions src/test/ui/consts/issue-87046.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 47a4184

Please sign in to comment.