mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Don't ICE on the use of integer addresses for ZST constants in pattern matching
This commit is contained in:
parent
3e0a1c0910
commit
1e40681f50
@ -127,6 +127,10 @@ impl<Tag> Allocation<Tag> {
|
||||
extra: (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zst(align: Align) -> Self {
|
||||
Self::undef(Size::ZERO, align)
|
||||
}
|
||||
}
|
||||
|
||||
impl Allocation<(), ()> {
|
||||
|
@ -237,11 +237,11 @@ use super::{FieldPat, Pat, PatKind, PatRange};
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::{HirId, RangeEnd};
|
||||
use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx};
|
||||
use rustc::ty::layout::{Align, Integer, IntegerExt, Size, VariantIdx};
|
||||
use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef};
|
||||
|
||||
use rustc::lint;
|
||||
use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
|
||||
use rustc::mir::interpret::{truncate, AllocId, Allocation, ConstValue, Pointer, Scalar};
|
||||
use rustc::mir::Field;
|
||||
use rustc::util::captures::Captures;
|
||||
use rustc::util::common::ErrorReported;
|
||||
@ -252,6 +252,7 @@ use syntax_pos::{Span, DUMMY_SP};
|
||||
use arena::TypedArena;
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::{self, max, min, Ordering};
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
@ -260,11 +261,12 @@ use std::ops::RangeInclusive;
|
||||
use std::u128;
|
||||
|
||||
pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> {
|
||||
LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat)
|
||||
LiteralExpander { tcx: cx.tcx, param_env: cx.param_env }.fold_pattern(&pat)
|
||||
}
|
||||
|
||||
struct LiteralExpander<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
}
|
||||
|
||||
impl LiteralExpander<'tcx> {
|
||||
@ -284,9 +286,23 @@ impl LiteralExpander<'tcx> {
|
||||
debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty);
|
||||
match (val, &crty.kind, &rty.kind) {
|
||||
// the easy case, deref a reference
|
||||
(ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => {
|
||||
let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id);
|
||||
ConstValue::ByRef { alloc, offset: p.offset }
|
||||
(ConstValue::Scalar(p), x, y) if x == y => {
|
||||
match p {
|
||||
Scalar::Ptr(p) => {
|
||||
let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id);
|
||||
ConstValue::ByRef { alloc, offset: p.offset }
|
||||
}
|
||||
Scalar::Raw { .. } => {
|
||||
let layout = self.tcx.layout_of(self.param_env.and(rty)).unwrap();
|
||||
if layout.is_zst() {
|
||||
// Deref of a reference to a ZST is a nop.
|
||||
ConstValue::Scalar(Scalar::zst())
|
||||
} else {
|
||||
// FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;`
|
||||
bug!("cannot deref {:#?}, {} -> {}", val, crty, rty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// unsize array to slice if pattern is array but match value or other patterns are slice
|
||||
(ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
|
||||
@ -2348,16 +2364,28 @@ fn specialize_one_pattern<'p, 'tcx>(
|
||||
// just integers. The only time they should be pointing to memory
|
||||
// is when they are subslices of nonzero slices.
|
||||
let (alloc, offset, n, ty) = match value.ty.kind {
|
||||
ty::Array(t, n) => match value.val {
|
||||
ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
|
||||
(alloc, offset, n.eval_usize(cx.tcx, cx.param_env), t)
|
||||
ty::Array(t, n) => {
|
||||
let n = n.eval_usize(cx.tcx, cx.param_env);
|
||||
match value.val {
|
||||
ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
|
||||
(Cow::Borrowed(alloc), offset, n, t)
|
||||
}
|
||||
ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. }))
|
||||
if n == 0 =>
|
||||
{
|
||||
let align = Align::from_bytes(data as u64).unwrap();
|
||||
// empty array
|
||||
(Cow::Owned(Allocation::zst(align)), Size::ZERO, 0, t)
|
||||
}
|
||||
_ => span_bug!(pat.span, "array pattern is {:?}", value,),
|
||||
}
|
||||
_ => span_bug!(pat.span, "array pattern is {:?}", value,),
|
||||
},
|
||||
}
|
||||
ty::Slice(t) => {
|
||||
match value.val {
|
||||
ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
|
||||
(data, Size::from_bytes(start as u64), (end - start) as u64, t)
|
||||
let offset = Size::from_bytes(start as u64);
|
||||
let n = (end - start) as u64;
|
||||
(Cow::Borrowed(data), offset, n, t)
|
||||
}
|
||||
ty::ConstKind::Value(ConstValue::ByRef { .. }) => {
|
||||
// FIXME(oli-obk): implement `deref` for `ConstValue`
|
||||
|
@ -993,6 +993,12 @@ pub fn compare_const_vals<'tcx>(
|
||||
return fallback();
|
||||
}
|
||||
|
||||
// Early return for equal constants (so e.g. references to ZSTs can be compared, even if they
|
||||
// are just integer addresses).
|
||||
if a.val == b.val {
|
||||
return from_bool(true);
|
||||
}
|
||||
|
||||
let a_bits = a.try_eval_bits(tcx, param_env, ty);
|
||||
let b_bits = b.try_eval_bits(tcx, param_env, ty);
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
// run-pass
|
||||
#![feature(const_transmute)]
|
||||
|
||||
const FOO: isize = 10;
|
||||
const BAR: isize = 3;
|
||||
const ZST: &() = unsafe { std::mem::transmute(1usize) };
|
||||
const ZST_ARR: &[u8; 0] = unsafe { std::mem::transmute(1usize) };
|
||||
|
||||
const fn foo() -> isize { 4 }
|
||||
const BOO: isize = foo();
|
||||
@ -15,4 +18,14 @@ pub fn main() {
|
||||
_ => 3
|
||||
};
|
||||
assert_eq!(y, 2);
|
||||
let z = match &() {
|
||||
ZST => 9,
|
||||
// FIXME: this should not be required
|
||||
_ => 42,
|
||||
};
|
||||
assert_eq!(z, 9);
|
||||
let z = match b"" {
|
||||
ZST_ARR => 10,
|
||||
};
|
||||
assert_eq!(z, 10);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user