]> git.lizzy.rs Git - rust.git/commitdiff
Don't depend on `Allocation` sizes for pattern length
authorOliver Scherer <github35764891676564198441@oli-obk.de>
Wed, 5 Dec 2018 17:31:49 +0000 (18:31 +0100)
committerOliver Scherer <github35764891676564198441@oli-obk.de>
Mon, 10 Dec 2018 15:34:44 +0000 (16:34 +0100)
src/librustc_mir/hair/pattern/_match.rs
src/librustc_mir/hair/pattern/mod.rs

index 4c77350f10ecd7182b8d058fade9b5a02978e614..601b08203fadab67f652eba3d8d425b0605412ca 100644 (file)
 
 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};
 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<bool, ErrorReported> {
     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()?;
index d695a64f62a08e1e2a1a1a211996e5807529cb5f..ddd6a705b04d116a8d1135d91d4342ef19e20552 100644 (file)
@@ -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);
                             }
                         }
                     }
                 }
-                _ => (),
             }
+            _ => (),
         }
     }