Skip to content

Commit a5a7fcb

Browse files
committed
Don't depend on Allocation sizes for pattern length
1 parent 3a75e80 commit a5a7fcb

File tree

2 files changed

+137
-68
lines changed

2 files changed

+137
-68
lines changed

src/librustc_mir/hair/pattern/_match.rs

+116-45
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,11 @@ use super::{PatternFoldable, PatternFolder, compare_const_vals};
178178

179179
use rustc::hir::def_id::DefId;
180180
use rustc::hir::RangeEnd;
181-
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
182-
use rustc::ty::layout::{Integer, IntegerExt, VariantIdx};
181+
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const};
182+
use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size};
183183

184184
use rustc::mir::Field;
185-
use rustc::mir::interpret::ConstValue;
185+
use rustc::mir::interpret::{ConstValue, Pointer, Scalar};
186186
use rustc::util::common::ErrorReported;
187187

188188
use syntax::attr::{SignedInt, UnsignedInt};
@@ -200,22 +200,66 @@ use std::u128;
200200
pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>)
201201
-> &'a Pattern<'tcx>
202202
{
203-
cx.pattern_arena.alloc(LiteralExpander.fold_pattern(&pat))
203+
cx.pattern_arena.alloc(LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat))
204204
}
205205

206-
struct LiteralExpander;
207-
impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
206+
struct LiteralExpander<'a, 'tcx> {
207+
tcx: TyCtxt<'a, 'tcx, 'tcx>
208+
}
209+
210+
impl<'a, 'tcx> LiteralExpander<'a, 'tcx> {
211+
/// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice
212+
fn fold_const_value_deref(
213+
&mut self,
214+
val: ConstValue<'tcx>,
215+
rty: Ty<'tcx>,
216+
crty: Ty<'tcx>,
217+
) -> ConstValue<'tcx> {
218+
match (val, &crty.sty, &rty.sty) {
219+
// the easy case, deref a reference
220+
(ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => ConstValue::ByRef(
221+
p.alloc_id,
222+
self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id),
223+
p.offset,
224+
),
225+
// unsize array to slice if pattern is array but match value or other patterns are slice
226+
(ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
227+
assert_eq!(t, u);
228+
ConstValue::ScalarPair(
229+
Scalar::Ptr(p),
230+
n.val.try_to_scalar().unwrap(),
231+
)
232+
},
233+
// fat pointers stay the same
234+
(ConstValue::ScalarPair(..), _, _) => val,
235+
// FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
236+
_ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
237+
}
238+
}
239+
}
240+
241+
impl<'a, 'tcx> PatternFolder<'tcx> for LiteralExpander<'a, 'tcx> {
208242
fn fold_pattern(&mut self, pat: &Pattern<'tcx>) -> Pattern<'tcx> {
209243
match (&pat.ty.sty, &*pat.kind) {
210-
(&ty::Ref(_, rty, _), &PatternKind::Constant { ref value }) => {
244+
(
245+
&ty::Ref(_, rty, _),
246+
&PatternKind::Constant { value: Const {
247+
val,
248+
ty: ty::TyS { sty: ty::Ref(_, crty, _), .. },
249+
} },
250+
) => {
211251
Pattern {
212252
ty: pat.ty,
213253
span: pat.span,
214254
kind: box PatternKind::Deref {
215255
subpattern: Pattern {
216256
ty: rty,
217257
span: pat.span,
218-
kind: box PatternKind::Constant { value: value.clone() },
258+
kind: box PatternKind::Constant { value: Const::from_const_value(
259+
self.tcx,
260+
self.fold_const_value_deref(*val, rty, crty),
261+
rty,
262+
) },
219263
}
220264
}
221265
}
@@ -732,15 +776,16 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
732776
for row in patterns {
733777
match *row.kind {
734778
PatternKind::Constant { value } => {
735-
if let Some(ptr) = value.to_ptr() {
736-
let is_array_ptr = value.ty
737-
.builtin_deref(true)
738-
.and_then(|t| t.ty.builtin_index())
739-
.map_or(false, |t| t == cx.tcx.types.u8);
740-
if is_array_ptr {
741-
let alloc = cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
742-
max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
743-
}
779+
match (value.val, &value.ty.sty) {
780+
(_, ty::Array(_, n)) => max_fixed_len = cmp::max(
781+
max_fixed_len,
782+
n.unwrap_usize(cx.tcx),
783+
),
784+
(ConstValue::ScalarPair(_, n), ty::Slice(_)) => max_fixed_len = cmp::max(
785+
max_fixed_len,
786+
n.to_usize(&cx.tcx).unwrap(),
787+
),
788+
_ => {},
744789
}
745790
}
746791
PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
@@ -1358,18 +1403,44 @@ fn slice_pat_covered_by_constructor<'tcx>(
13581403
) -> Result<bool, ErrorReported> {
13591404
let data: &[u8] = match *ctor {
13601405
ConstantValue(const_val) => {
1361-
let val = match const_val.val {
1362-
ConstValue::Unevaluated(..) |
1363-
ConstValue::ByRef(..) => bug!("unexpected ConstValue: {:?}", const_val),
1364-
ConstValue::Scalar(val) | ConstValue::ScalarPair(val, _) => val,
1365-
};
1366-
if let Ok(ptr) = val.to_ptr() {
1367-
tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id).bytes.as_ref()
1368-
} else {
1369-
bug!("unexpected non-ptr ConstantValue")
1406+
match (const_val.val, &const_val.ty.sty) {
1407+
(ConstValue::ByRef(id, alloc, offset), ty::Array(t, n)) => {
1408+
if *t != tcx.types.u8 {
1409+
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
1410+
// any sort of exhaustiveness/unreachable check yet
1411+
return Ok(false);
1412+
}
1413+
let ptr = Pointer::new(id, offset);
1414+
let n = n.assert_usize(tcx).unwrap();
1415+
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
1416+
},
1417+
(ConstValue::ScalarPair(Scalar::Bits { .. }, n), ty::Slice(_)) => {
1418+
assert_eq!(n.to_usize(&tcx).unwrap(), 0);
1419+
&[]
1420+
},
1421+
(ConstValue::ScalarPair(Scalar::Ptr(ptr), n), ty::Slice(t)) => {
1422+
if *t != tcx.types.u8 {
1423+
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
1424+
// any sort of exhaustiveness/unreachable check yet
1425+
return Ok(false);
1426+
}
1427+
let n = n.to_usize(&tcx).unwrap();
1428+
tcx.alloc_map
1429+
.lock()
1430+
.unwrap_memory(ptr.alloc_id)
1431+
.get_bytes(&tcx, ptr, Size::from_bytes(n))
1432+
.unwrap()
1433+
},
1434+
_ => bug!(
1435+
"slice_pat_covered_by_constructor: {:#?}, {:#?}, {:#?}, {:#?}",
1436+
ctor, prefix, slice, suffix,
1437+
),
13701438
}
13711439
}
1372-
_ => bug!()
1440+
_ => bug!(
1441+
"slice_pat_covered_by_constructor not ConstValue: {:#?}, {:#?}, {:#?}, {:#?}",
1442+
ctor, prefix, slice, suffix,
1443+
),
13731444
};
13741445

13751446
let pat_len = prefix.len() + suffix.len();
@@ -1675,22 +1746,23 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
16751746
// necessarily point to memory, they are usually just integers. The only time
16761747
// they should be pointing to memory is when they are subslices of nonzero
16771748
// slices
1678-
let (opt_ptr, n, ty) = match value.ty.builtin_deref(false).unwrap().ty.sty {
1679-
ty::TyKind::Array(t, n) => (value.to_ptr(), n.unwrap_usize(cx.tcx), t),
1680-
ty::TyKind::Slice(t) => {
1681-
match value.val {
1682-
ConstValue::ScalarPair(ptr, n) => (
1683-
ptr.to_ptr().ok(),
1684-
n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64,
1685-
t,
1686-
),
1687-
_ => span_bug!(
1688-
pat.span,
1689-
"slice pattern constant must be scalar pair but is {:?}",
1690-
value,
1691-
),
1692-
}
1693-
},
1749+
let (opt_ptr, n, ty) = match (value.val, &value.ty.sty) {
1750+
(ConstValue::ByRef(id, alloc, offset), ty::TyKind::Array(t, n)) => (
1751+
Some((
1752+
Pointer::new(id, offset),
1753+
alloc,
1754+
)),
1755+
n.unwrap_usize(cx.tcx),
1756+
t,
1757+
),
1758+
(ConstValue::ScalarPair(ptr, n), ty::TyKind::Slice(t)) => (
1759+
ptr.to_ptr().ok().map(|ptr| (
1760+
ptr,
1761+
cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
1762+
)),
1763+
n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64,
1764+
t,
1765+
),
16941766
_ => span_bug!(
16951767
pat.span,
16961768
"unexpected const-val {:?} with ctor {:?}",
@@ -1702,8 +1774,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
17021774
// convert a constant slice/array pattern to a list of patterns.
17031775
match (n, opt_ptr) {
17041776
(0, _) => Some(SmallVec::new()),
1705-
(_, Some(ptr)) => {
1706-
let alloc = cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
1777+
(_, Some((ptr, alloc))) => {
17071778
let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
17081779
(0..n).map(|i| {
17091780
let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;

src/librustc_mir/hair/pattern/mod.rs

+21-23
Original file line numberDiff line numberDiff line change
@@ -1259,34 +1259,32 @@ pub fn compare_const_vals<'a, 'tcx>(
12591259
}
12601260
}
12611261

1262-
if let ty::Ref(_, rty, _) = ty.value.sty {
1263-
if let ty::Str = rty.sty {
1264-
match (a.val, b.val) {
1265-
(
1266-
ConstValue::ScalarPair(
1267-
Scalar::Ptr(ptr_a),
1268-
len_a,
1269-
),
1270-
ConstValue::ScalarPair(
1271-
Scalar::Ptr(ptr_b),
1272-
len_b,
1273-
),
1274-
) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => {
1275-
if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) {
1276-
if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) {
1277-
if len_a == len_b {
1278-
let map = tcx.alloc_map.lock();
1279-
let alloc_a = map.unwrap_memory(ptr_a.alloc_id);
1280-
let alloc_b = map.unwrap_memory(ptr_b.alloc_id);
1281-
if alloc_a.bytes.len() as u128 == len_a {
1282-
return from_bool(alloc_a == alloc_b);
1283-
}
1262+
if let ty::Str = ty.value.sty {
1263+
match (a.val, b.val) {
1264+
(
1265+
ConstValue::ScalarPair(
1266+
Scalar::Ptr(ptr_a),
1267+
len_a,
1268+
),
1269+
ConstValue::ScalarPair(
1270+
Scalar::Ptr(ptr_b),
1271+
len_b,
1272+
),
1273+
) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => {
1274+
if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) {
1275+
if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) {
1276+
if len_a == len_b {
1277+
let map = tcx.alloc_map.lock();
1278+
let alloc_a = map.unwrap_memory(ptr_a.alloc_id);
1279+
let alloc_b = map.unwrap_memory(ptr_b.alloc_id);
1280+
if alloc_a.bytes.len() as u128 == len_a {
1281+
return from_bool(alloc_a == alloc_b);
12841282
}
12851283
}
12861284
}
12871285
}
1288-
_ => (),
12891286
}
1287+
_ => (),
12901288
}
12911289
}
12921290

0 commit comments

Comments
 (0)