From a5a7fcbde390ce3545613d7deeba25d0d400d818 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 5 Dec 2018 18:31:49 +0100 Subject: [PATCH] Don't depend on `Allocation` sizes for pattern length --- src/librustc_mir/hair/pattern/_match.rs | 161 +++++++++++++++++------- src/librustc_mir/hair/pattern/mod.rs | 44 ++++--- 2 files changed, 137 insertions(+), 68 deletions(-) diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 4c77350f10e..601b08203fa 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -178,11 +178,11 @@ use rustc::hir::def_id::DefId; use rustc::hir::RangeEnd; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::ty::layout::{Integer, IntegerExt, VariantIdx}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const}; +use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size}; use rustc::mir::Field; -use rustc::mir::interpret::ConstValue; +use rustc::mir::interpret::{ConstValue, Pointer, Scalar}; use rustc::util::common::ErrorReported; use syntax::attr::{SignedInt, UnsignedInt}; @@ -200,14 +200,54 @@ pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>) -> &'a Pattern<'tcx> { - cx.pattern_arena.alloc(LiteralExpander.fold_pattern(&pat)) + cx.pattern_arena.alloc(LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat)) } -struct LiteralExpander; -impl<'tcx> PatternFolder<'tcx> for LiteralExpander { +struct LiteralExpander<'a, 'tcx> { + tcx: TyCtxt<'a, 'tcx, 'tcx> +} + +impl<'a, 'tcx> LiteralExpander<'a, 'tcx> { + /// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice + fn fold_const_value_deref( + &mut self, + val: ConstValue<'tcx>, + rty: Ty<'tcx>, + crty: Ty<'tcx>, + ) -> ConstValue<'tcx> { + match (val, &crty.sty, &rty.sty) { + // the easy case, deref a reference + (ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => ConstValue::ByRef( + p.alloc_id, + self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id), + p.offset, + ), + // 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)) => { + assert_eq!(t, u); + ConstValue::ScalarPair( + Scalar::Ptr(p), + n.val.try_to_scalar().unwrap(), + ) + }, + // fat pointers stay the same + (ConstValue::ScalarPair(..), _, _) => val, + // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used + _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty), + } + } +} + +impl<'a, 'tcx> PatternFolder<'tcx> for LiteralExpander<'a, 'tcx> { fn fold_pattern(&mut self, pat: &Pattern<'tcx>) -> Pattern<'tcx> { match (&pat.ty.sty, &*pat.kind) { - (&ty::Ref(_, rty, _), &PatternKind::Constant { ref value }) => { + ( + &ty::Ref(_, rty, _), + &PatternKind::Constant { value: Const { + val, + ty: ty::TyS { sty: ty::Ref(_, crty, _), .. }, + } }, + ) => { Pattern { ty: pat.ty, span: pat.span, @@ -215,7 +255,11 @@ fn fold_pattern(&mut self, pat: &Pattern<'tcx>) -> Pattern<'tcx> { subpattern: Pattern { ty: rty, span: pat.span, - kind: box PatternKind::Constant { value: value.clone() }, + kind: box PatternKind::Constant { value: Const::from_const_value( + self.tcx, + self.fold_const_value_deref(*val, rty, crty), + rty, + ) }, } } } @@ -732,15 +776,16 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( for row in patterns { match *row.kind { PatternKind::Constant { value } => { - if let Some(ptr) = value.to_ptr() { - let is_array_ptr = value.ty - .builtin_deref(true) - .and_then(|t| t.ty.builtin_index()) - .map_or(false, |t| t == cx.tcx.types.u8); - if is_array_ptr { - let alloc = cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); - max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64); - } + match (value.val, &value.ty.sty) { + (_, ty::Array(_, n)) => max_fixed_len = cmp::max( + max_fixed_len, + n.unwrap_usize(cx.tcx), + ), + (ConstValue::ScalarPair(_, n), ty::Slice(_)) => max_fixed_len = cmp::max( + max_fixed_len, + n.to_usize(&cx.tcx).unwrap(), + ), + _ => {}, } } PatternKind::Slice { ref prefix, slice: None, ref suffix } => { @@ -1358,18 +1403,44 @@ fn slice_pat_covered_by_constructor<'tcx>( ) -> Result { let data: &[u8] = match *ctor { ConstantValue(const_val) => { - let val = match const_val.val { - ConstValue::Unevaluated(..) | - ConstValue::ByRef(..) => bug!("unexpected ConstValue: {:?}", const_val), - ConstValue::Scalar(val) | ConstValue::ScalarPair(val, _) => val, - }; - if let Ok(ptr) = val.to_ptr() { - tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id).bytes.as_ref() - } else { - bug!("unexpected non-ptr ConstantValue") + match (const_val.val, &const_val.ty.sty) { + (ConstValue::ByRef(id, alloc, offset), ty::Array(t, n)) => { + if *t != tcx.types.u8 { + // FIXME(oli-obk): can't mix const patterns with slice patterns and get + // any sort of exhaustiveness/unreachable check yet + return Ok(false); + } + let ptr = Pointer::new(id, offset); + let n = n.assert_usize(tcx).unwrap(); + alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap() + }, + (ConstValue::ScalarPair(Scalar::Bits { .. }, n), ty::Slice(_)) => { + assert_eq!(n.to_usize(&tcx).unwrap(), 0); + &[] + }, + (ConstValue::ScalarPair(Scalar::Ptr(ptr), n), ty::Slice(t)) => { + if *t != tcx.types.u8 { + // FIXME(oli-obk): can't mix const patterns with slice patterns and get + // any sort of exhaustiveness/unreachable check yet + return Ok(false); + } + let n = n.to_usize(&tcx).unwrap(); + tcx.alloc_map + .lock() + .unwrap_memory(ptr.alloc_id) + .get_bytes(&tcx, ptr, Size::from_bytes(n)) + .unwrap() + }, + _ => bug!( + "slice_pat_covered_by_constructor: {:#?}, {:#?}, {:#?}, {:#?}", + ctor, prefix, slice, suffix, + ), } } - _ => bug!() + _ => bug!( + "slice_pat_covered_by_constructor not ConstValue: {:#?}, {:#?}, {:#?}, {:#?}", + ctor, prefix, slice, suffix, + ), }; let pat_len = prefix.len() + suffix.len(); @@ -1675,22 +1746,23 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( // necessarily point to memory, they are usually just integers. The only time // they should be pointing to memory is when they are subslices of nonzero // slices - let (opt_ptr, n, ty) = match value.ty.builtin_deref(false).unwrap().ty.sty { - ty::TyKind::Array(t, n) => (value.to_ptr(), n.unwrap_usize(cx.tcx), t), - ty::TyKind::Slice(t) => { - match value.val { - ConstValue::ScalarPair(ptr, n) => ( - ptr.to_ptr().ok(), - n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64, - t, - ), - _ => span_bug!( - pat.span, - "slice pattern constant must be scalar pair but is {:?}", - value, - ), - } - }, + let (opt_ptr, n, ty) = match (value.val, &value.ty.sty) { + (ConstValue::ByRef(id, alloc, offset), ty::TyKind::Array(t, n)) => ( + Some(( + Pointer::new(id, offset), + alloc, + )), + n.unwrap_usize(cx.tcx), + t, + ), + (ConstValue::ScalarPair(ptr, n), ty::TyKind::Slice(t)) => ( + ptr.to_ptr().ok().map(|ptr| ( + ptr, + cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), + )), + n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64, + t, + ), _ => span_bug!( pat.span, "unexpected const-val {:?} with ctor {:?}", @@ -1702,8 +1774,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( // convert a constant slice/array pattern to a list of patterns. match (n, opt_ptr) { (0, _) => Some(SmallVec::new()), - (_, Some(ptr)) => { - let alloc = cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); + (_, Some((ptr, alloc))) => { let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?; (0..n).map(|i| { let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?; diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index d695a64f62a..ddd6a705b04 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -1259,34 +1259,32 @@ pub fn compare_const_vals<'a, 'tcx>( } } - if let ty::Ref(_, rty, _) = ty.value.sty { - if let ty::Str = rty.sty { - match (a.val, b.val) { - ( - ConstValue::ScalarPair( - Scalar::Ptr(ptr_a), - len_a, - ), - ConstValue::ScalarPair( - Scalar::Ptr(ptr_b), - len_b, - ), - ) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => { - if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) { - if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) { - if len_a == len_b { - let map = tcx.alloc_map.lock(); - let alloc_a = map.unwrap_memory(ptr_a.alloc_id); - let alloc_b = map.unwrap_memory(ptr_b.alloc_id); - if alloc_a.bytes.len() as u128 == len_a { - return from_bool(alloc_a == alloc_b); - } + if let ty::Str = ty.value.sty { + match (a.val, b.val) { + ( + ConstValue::ScalarPair( + Scalar::Ptr(ptr_a), + len_a, + ), + ConstValue::ScalarPair( + Scalar::Ptr(ptr_b), + len_b, + ), + ) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => { + if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) { + if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) { + if len_a == len_b { + let map = tcx.alloc_map.lock(); + let alloc_a = map.unwrap_memory(ptr_a.alloc_id); + let alloc_b = map.unwrap_memory(ptr_b.alloc_id); + if alloc_a.bytes.len() as u128 == len_a { + return from_bool(alloc_a == alloc_b); } } } } - _ => (), } + _ => (), } } -- 2.44.0