Skip to content

Commit a247b06

Browse files
committed
Don't ICE on the use of integer addresses for ZST constants in pattern matching
1 parent 01a4650 commit a247b06

File tree

4 files changed

+61
-11
lines changed

4 files changed

+61
-11
lines changed

src/librustc/mir/interpret/allocation.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ impl<Tag> Allocation<Tag> {
127127
extra: (),
128128
}
129129
}
130+
131+
pub fn zst(align: Align) -> Self {
132+
Self::undef(Size::ZERO, align)
133+
}
130134
}
131135

132136
impl Allocation<(), ()> {

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -237,11 +237,11 @@ use super::{FieldPat, Pat, PatKind, PatRange};
237237

238238
use rustc::hir::def_id::DefId;
239239
use rustc::hir::{HirId, RangeEnd};
240-
use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx};
240+
use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx, Align};
241241
use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef};
242242

243243
use rustc::lint;
244-
use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
244+
use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar, Allocation};
245245
use rustc::mir::Field;
246246
use rustc::util::captures::Captures;
247247
use rustc::util::common::ErrorReported;
@@ -258,13 +258,15 @@ use std::fmt;
258258
use std::iter::{FromIterator, IntoIterator};
259259
use std::ops::RangeInclusive;
260260
use std::u128;
261+
use std::borrow::Cow;
261262

262263
pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> {
263-
LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat)
264+
LiteralExpander { tcx: cx.tcx, param_env: cx.param_env }.fold_pattern(&pat)
264265
}
265266

266267
struct LiteralExpander<'tcx> {
267268
tcx: TyCtxt<'tcx>,
269+
param_env: ty::ParamEnv<'tcx>,
268270
}
269271

270272
impl LiteralExpander<'tcx> {
@@ -284,9 +286,23 @@ impl LiteralExpander<'tcx> {
284286
debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty);
285287
match (val, &crty.kind, &rty.kind) {
286288
// the easy case, deref a reference
287-
(ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => {
288-
let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id);
289-
ConstValue::ByRef { alloc, offset: p.offset }
289+
(ConstValue::Scalar(p), x, y) if x == y => {
290+
match p {
291+
Scalar::Ptr(p) => {
292+
let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id);
293+
ConstValue::ByRef { alloc, offset: p.offset }
294+
},
295+
Scalar::Raw { .. } => {
296+
let layout = self.tcx.layout_of(self.param_env.and(rty)).unwrap();
297+
if layout.is_zst() {
298+
// Deref of a reference to a ZST is a nop.
299+
ConstValue::Scalar(Scalar::zst())
300+
} else {
301+
// FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;`
302+
bug!("cannot deref {:#?}, {} -> {}", val, crty, rty);
303+
}
304+
}
305+
}
290306
}
291307
// unsize array to slice if pattern is array but match value or other patterns are slice
292308
(ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
@@ -2347,16 +2363,27 @@ fn specialize_one_pattern<'p, 'tcx>(
23472363
// just integers. The only time they should be pointing to memory
23482364
// is when they are subslices of nonzero slices.
23492365
let (alloc, offset, n, ty) = match value.ty.kind {
2350-
ty::Array(t, n) => match value.val {
2351-
ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
2352-
(alloc, offset, n.eval_usize(cx.tcx, cx.param_env), t)
2366+
ty::Array(t, n) => {
2367+
let n = n.eval_usize(cx.tcx, cx.param_env);
2368+
match value.val {
2369+
ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
2370+
(Cow::Borrowed(alloc), offset, n, t)
2371+
}
2372+
ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. }))
2373+
if n == 0 => {
2374+
let align = Align::from_bytes(data as u64).unwrap();
2375+
// empty array
2376+
(Cow::Owned(Allocation::zst(align)), Size::ZERO, 0, t)
2377+
}
2378+
_ => span_bug!(pat.span, "array pattern is {:?}", value,),
23532379
}
2354-
_ => span_bug!(pat.span, "array pattern is {:?}", value,),
23552380
},
23562381
ty::Slice(t) => {
23572382
match value.val {
23582383
ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
2359-
(data, Size::from_bytes(start as u64), (end - start) as u64, t)
2384+
let offset = Size::from_bytes(start as u64);
2385+
let n = (end - start) as u64;
2386+
(Cow::Borrowed(data), offset, n, t)
23602387
}
23612388
ty::ConstKind::Value(ConstValue::ByRef { .. }) => {
23622389
// FIXME(oli-obk): implement `deref` for `ConstValue`

src/librustc_mir/hair/pattern/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,12 @@ pub fn compare_const_vals<'tcx>(
11631163
return fallback();
11641164
}
11651165

1166+
// Early return for equal constants (so e.g. references to ZSTs can be compared, even if they
1167+
// are just integer addresses).
1168+
if a.val == b.val {
1169+
return from_bool(true);
1170+
}
1171+
11661172
let a_bits = a.try_eval_bits(tcx, param_env, ty);
11671173
let b_bits = b.try_eval_bits(tcx, param_env, ty);
11681174

src/test/ui/consts/consts-in-patterns.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
// run-pass
2+
#![feature(const_transmute)]
23

34
const FOO: isize = 10;
45
const BAR: isize = 3;
6+
const ZST: &() = unsafe { std::mem::transmute(1usize) };
7+
const ZST_ARR: &[u8; 0] = unsafe { std::mem::transmute(1usize) };
58

69
const fn foo() -> isize { 4 }
710
const BOO: isize = foo();
@@ -15,4 +18,14 @@ pub fn main() {
1518
_ => 3
1619
};
1720
assert_eq!(y, 2);
21+
let z = match &() {
22+
ZST => 9,
23+
// FIXME: this should not be required
24+
_ => 42,
25+
};
26+
assert_eq!(z, 9);
27+
let z = match b"" {
28+
ZST_ARR => 10,
29+
};
30+
assert_eq!(z, 10);
1831
}

0 commit comments

Comments
 (0)