Skip to content

Commit 1e40681

Browse files
committed
Don't ICE on the use of integer addresses for ZST constants in pattern matching
1 parent 3e0a1c0 commit 1e40681

File tree

4 files changed

+63
-12
lines changed

4 files changed

+63
-12
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: 40 additions & 12 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::{Align, Integer, IntegerExt, Size, VariantIdx};
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, Allocation, ConstValue, Pointer, Scalar};
245245
use rustc::mir::Field;
246246
use rustc::util::captures::Captures;
247247
use rustc::util::common::ErrorReported;
@@ -252,6 +252,7 @@ use syntax_pos::{Span, DUMMY_SP};
252252
use arena::TypedArena;
253253

254254
use smallvec::{smallvec, SmallVec};
255+
use std::borrow::Cow;
255256
use std::cmp::{self, max, min, Ordering};
256257
use std::convert::TryInto;
257258
use std::fmt;
@@ -260,11 +261,12 @@ use std::ops::RangeInclusive;
260261
use std::u128;
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)) => {
@@ -2348,16 +2364,28 @@ fn specialize_one_pattern<'p, 'tcx>(
23482364
// just integers. The only time they should be pointing to memory
23492365
// is when they are subslices of nonzero slices.
23502366
let (alloc, offset, n, ty) = match value.ty.kind {
2351-
ty::Array(t, n) => match value.val {
2352-
ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
2353-
(alloc, offset, n.eval_usize(cx.tcx, cx.param_env), t)
2367+
ty::Array(t, n) => {
2368+
let n = n.eval_usize(cx.tcx, cx.param_env);
2369+
match value.val {
2370+
ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
2371+
(Cow::Borrowed(alloc), offset, n, t)
2372+
}
2373+
ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. }))
2374+
if n == 0 =>
2375+
{
2376+
let align = Align::from_bytes(data as u64).unwrap();
2377+
// empty array
2378+
(Cow::Owned(Allocation::zst(align)), Size::ZERO, 0, t)
2379+
}
2380+
_ => span_bug!(pat.span, "array pattern is {:?}", value,),
23542381
}
2355-
_ => span_bug!(pat.span, "array pattern is {:?}", value,),
2356-
},
2382+
}
23572383
ty::Slice(t) => {
23582384
match value.val {
23592385
ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
2360-
(data, Size::from_bytes(start as u64), (end - start) as u64, t)
2386+
let offset = Size::from_bytes(start as u64);
2387+
let n = (end - start) as u64;
2388+
(Cow::Borrowed(data), offset, n, t)
23612389
}
23622390
ty::ConstKind::Value(ConstValue::ByRef { .. }) => {
23632391
// 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
@@ -993,6 +993,12 @@ pub fn compare_const_vals<'tcx>(
993993
return fallback();
994994
}
995995

996+
// Early return for equal constants (so e.g. references to ZSTs can be compared, even if they
997+
// are just integer addresses).
998+
if a.val == b.val {
999+
return from_bool(true);
1000+
}
1001+
9961002
let a_bits = a.try_eval_bits(tcx, param_env, ty);
9971003
let b_bits = b.try_eval_bits(tcx, param_env, ty);
9981004

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)