]> git.lizzy.rs Git - rust.git/commitdiff
Fully handle RawNullablePointer layout.
authorScott Olson <scott@solson.me>
Sat, 30 Apr 2016 07:04:17 +0000 (01:04 -0600)
committerScott Olson <scott@solson.me>
Sat, 30 Apr 2016 07:04:17 +0000 (01:04 -0600)
src/interpreter.rs
src/memory.rs
tests/compile-fail/bugs/option_box_transmute_ptr.rs [deleted file]
tests/run-pass/option_box_transmute_ptr.rs [new file with mode: 0644]

index 66a75dd4d56b25656698e3ea1093509ec8f4904f..4ab2413e0ffe2b70097dc6abb27e913e6ec6ee17 100644 (file)
@@ -256,18 +256,34 @@ fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>)
             Switch { ref discr, ref targets, adt_def } => {
                 let adt_ptr = try!(self.eval_lvalue(discr)).to_ptr();
                 let adt_layout = self.type_layout(self.lvalue_ty(discr));
-                let discr_size = match *adt_layout {
-                    Layout::General { discr, .. } => discr.size().bytes(),
-                    _ => panic!("attmpted to switch on non-aggregate type"),
-                };
-                let discr_val = try!(self.memory.read_uint(adt_ptr, discr_size as usize));
 
-                let matching = adt_def.variants.iter()
-                    .position(|v| discr_val == v.disr_val.to_u64_unchecked());
+                 match *adt_layout {
+                    Layout::General { discr, .. } => {
+                        let discr_size = discr.size().bytes();
+                        let discr_val = try!(self.memory.read_uint(adt_ptr, discr_size as usize));
+
+                        let matching = adt_def.variants.iter()
+                            .position(|v| discr_val == v.disr_val.to_u64_unchecked());
 
-                match matching {
-                    Some(i) => TerminatorTarget::Block(targets[i]),
-                    None => return Err(EvalError::InvalidDiscriminant),
+                        match matching {
+                            Some(i) => TerminatorTarget::Block(targets[i]),
+                            None => return Err(EvalError::InvalidDiscriminant),
+                        }
+                    }
+
+                    Layout::RawNullablePointer { nndiscr, .. } => {
+                        let is_null = match self.memory.read_usize(adt_ptr) {
+                            Ok(0) => true,
+                            Ok(_) | Err(EvalError::ReadPointerAsBytes) => false,
+                            Err(e) => return Err(e),
+                        };
+
+                        assert!(nndiscr == 0 || nndiscr == 1);
+                        let target = if is_null { 1 - nndiscr } else { nndiscr };
+                        TerminatorTarget::Block(targets[target as usize])
+                    }
+
+                    _ => panic!("attmpted to switch on non-aggregate type"),
                 }
             }
 
@@ -633,7 +649,7 @@ fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<'
                     Layout::Array { .. } => {
                         let elem_size = match dest_ty.sty {
                             ty::TyArray(elem_ty, _) => self.type_size(elem_ty) as u64,
-                            _ => panic!("tried to assign {:?} aggregate to non-array type {:?}",
+                            _ => panic!("tried to assign {:?} to non-array type {:?}",
                                         kind, dest_ty),
                         };
                         let offsets = (0..).map(|i| i * elem_size);
@@ -650,7 +666,24 @@ fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<'
                                 .map(|s| s.bytes());
                             try!(self.assign_fields(dest, offsets, operands));
                         } else {
-                            panic!("tried to assign {:?} aggregate to Layout::General dest", kind);
+                            panic!("tried to assign {:?} to Layout::General", kind);
+                        }
+                    }
+
+                    Layout::RawNullablePointer { nndiscr, .. } => {
+                        if let mir::AggregateKind::Adt(_, variant, _) = *kind {
+                            if nndiscr == variant as u64 {
+                                assert_eq!(operands.len(), 1);
+                                let operand = &operands[0];
+                                let src = try!(self.eval_operand(operand));
+                                let src_ty = self.operand_ty(operand);
+                                try!(self.move_(src, dest, src_ty));
+                            } else {
+                                assert_eq!(operands.len(), 0);
+                                try!(self.memory.write_isize(dest, 0));
+                            }
+                        } else {
+                            panic!("tried to assign {:?} to Layout::RawNullablePointer", kind);
                         }
                     }
 
@@ -788,6 +821,10 @@ fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<Lvalue> {
                                     panic!("field access on enum had no variant index");
                                 }
                             }
+                            Layout::RawNullablePointer { .. } => {
+                                assert_eq!(field.index(), 0);
+                                return Ok(base);
+                            }
                             _ => panic!("field access on non-product type: {:?}", base_layout),
                         };
 
@@ -802,6 +839,7 @@ fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<Lvalue> {
                                 extra: LvalueExtra::DowncastVariant(variant),
                             });
                         }
+                        Layout::RawNullablePointer { .. } => return Ok(base),
                         _ => panic!("variant downcast on non-aggregate type: {:?}", base_layout),
                     },
 
index 9f4e2691bcce572718e3af4c544f91b55b5f5c08..f48d5a9b8e8f75f018dbfc6cebb8b6cc29566f64 100644 (file)
@@ -403,7 +403,7 @@ fn copy_relocations(&mut self, src: Pointer, dest: Pointer, size: usize) -> Eval
     // Undefined bytes
     ////////////////////////////////////////////////////////////////////////////////
 
-    // FIXME(tsino): This is a very naive, slow version.
+    // FIXME(tsion): This is a very naive, slow version.
     fn copy_undef_mask(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<()> {
         // The bits have to be saved locally before writing to dest in case src and dest overlap.
         let mut v = Vec::with_capacity(size);
diff --git a/tests/compile-fail/bugs/option_box_transmute_ptr.rs b/tests/compile-fail/bugs/option_box_transmute_ptr.rs
deleted file mode 100644 (file)
index 84161da..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#![feature(custom_attribute)]
-#![allow(dead_code, unused_attributes)]
-
-#[miri_run]
-fn option_box_deref() -> i32 {
-    let val = Some(Box::new(42));
-    unsafe {
-        let ptr: *const i32 = std::mem::transmute(val); //~ ERROR: pointer offset outside bounds of allocation
-        *ptr
-    }
-}
-
-fn main() {}
diff --git a/tests/run-pass/option_box_transmute_ptr.rs b/tests/run-pass/option_box_transmute_ptr.rs
new file mode 100644 (file)
index 0000000..55beb11
--- /dev/null
@@ -0,0 +1,15 @@
+#![feature(custom_attribute)]
+#![allow(dead_code, unused_attributes)]
+
+// This tests that the size of Option<Box<i32>> is the same as *const i32.
+
+#[miri_run]
+fn option_box_deref() -> i32 {
+    let val = Some(Box::new(42));
+    unsafe {
+        let ptr: *const i32 = std::mem::transmute::<Option<Box<i32>>, *const i32>(val);
+        *ptr
+    }
+}
+
+fn main() {}