about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2012-12-18 14:35:08 -0800
committerGraydon Hoare <graydon@mozilla.com>2012-12-18 14:35:20 -0800
commit6d4fbd4f9ecd914ea85cedd9af89cb3dd3831f8f (patch)
tree635c9f053d811a6cd3874b582ee3406a3a526c72 /src
parentb46e25bdc8f4c0ac702a3197ef61da2786bb917c (diff)
downloadrust-6d4fbd4f9ecd914ea85cedd9af89cb3dd3831f8f.tar.gz
rust-6d4fbd4f9ecd914ea85cedd9af89cb3dd3831f8f.zip
core: fix remaining repr bugs, r=burningtree.
Diffstat (limited to 'src')
-rw-r--r--src/libcore/reflect.rs7
-rw-r--r--src/libcore/repr.rs106
2 files changed, 103 insertions, 10 deletions
diff --git a/src/libcore/reflect.rs b/src/libcore/reflect.rs
index 28c6031263b..268d5e1baa6 100644
--- a/src/libcore/reflect.rs
+++ b/src/libcore/reflect.rs
@@ -28,6 +28,8 @@ use libc::c_void;
  */
 pub trait MovePtr {
     fn move_ptr(adjustment: fn(*c_void) -> *c_void);
+    fn push_ptr();
+    fn pop_ptr();
 }
 
 /// Helper function for alignment calculation.
@@ -402,6 +404,7 @@ impl<V: TyVisitor MovePtr> MovePtrAdaptor<V>: TyVisitor {
                                 disr_val: int,
                                 n_fields: uint,
                                 name: &str) -> bool {
+        self.inner.push_ptr();
         if ! self.inner.visit_enter_enum_variant(variant, disr_val,
                                                  n_fields, name) {
             return false;
@@ -410,7 +413,9 @@ impl<V: TyVisitor MovePtr> MovePtrAdaptor<V>: TyVisitor {
     }
 
     fn visit_enum_variant_field(i: uint, inner: *TyDesc) -> bool {
+        unsafe { self.align((*inner).align); }
         if ! self.inner.visit_enum_variant_field(i, inner) { return false; }
+        unsafe { self.bump((*inner).size); }
         true
     }
 
@@ -422,6 +427,7 @@ impl<V: TyVisitor MovePtr> MovePtrAdaptor<V>: TyVisitor {
                                                  n_fields, name) {
             return false;
         }
+        self.inner.pop_ptr();
         true
     }
 
@@ -429,6 +435,7 @@ impl<V: TyVisitor MovePtr> MovePtrAdaptor<V>: TyVisitor {
         if ! self.inner.visit_leave_enum(n_variants, sz, align) {
             return false;
         }
+        self.bump(sz);
         true
     }
 
diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs
index d3ed4f31515..111070e5b24 100644
--- a/src/libcore/repr.rs
+++ b/src/libcore/repr.rs
@@ -26,6 +26,7 @@ use reflect::{MovePtr, MovePtrAdaptor, align};
 use vec::UnboxedVecRepr;
 use vec::raw::{VecRepr, SliceRepr};
 pub use managed::raw::BoxRepr;
+use dvec::DVec;
 
 /// Helpers
 
@@ -121,12 +122,23 @@ impl char : Repr {
 
 // New implementation using reflect::MovePtr
 
+enum VariantState {
+    Degenerate,
+    TagMatch,
+    TagMismatch,
+}
+
 pub struct ReprVisitor {
     mut ptr: *c_void,
+    ptr_stk: DVec<*c_void>,
+    var_stk: DVec<VariantState>,
     writer: @Writer
 }
 pub fn ReprVisitor(ptr: *c_void, writer: @Writer) -> ReprVisitor {
-    ReprVisitor { ptr: ptr, writer: writer }
+    ReprVisitor { ptr: ptr,
+                  ptr_stk: DVec(),
+                  var_stk: DVec(),
+                  writer: writer }
 }
 
 impl ReprVisitor : MovePtr {
@@ -134,6 +146,12 @@ impl ReprVisitor : MovePtr {
     fn move_ptr(adjustment: fn(*c_void) -> *c_void) {
         self.ptr = adjustment(self.ptr);
     }
+    fn push_ptr() {
+        self.ptr_stk.push(self.ptr);
+    }
+    fn pop_ptr() {
+        self.ptr = self.ptr_stk.pop();
+    }
 }
 
 impl ReprVisitor {
@@ -149,6 +167,18 @@ impl ReprVisitor {
     }
 
     #[inline(always)]
+    fn bump(sz: uint) {
+      do self.move_ptr() |p| {
+            ((p as uint) + sz) as *c_void
+      };
+    }
+
+    #[inline(always)]
+    fn bump_past<T>() {
+        self.bump(sys::size_of::<T>());
+    }
+
+    #[inline(always)]
     fn visit_inner(inner: *TyDesc) -> bool {
         self.visit_ptr_inner(self.ptr, inner)
     }
@@ -402,23 +432,79 @@ impl ReprVisitor : TyVisitor {
         true
     }
 
-    fn visit_enter_enum(_n_variants: uint,
+    fn visit_enter_enum(n_variants: uint,
                         _sz: uint, _align: uint) -> bool {
+        if n_variants == 1 {
+            self.var_stk.push(Degenerate)
+        } else {
+            self.var_stk.push(TagMatch)
+        }
         true
     }
     fn visit_enter_enum_variant(_variant: uint,
-                                _disr_val: int,
-                                _n_fields: uint,
-                                _name: &str) -> bool { true }
-    fn visit_enum_variant_field(_i: uint, inner: *TyDesc) -> bool {
-        self.visit_inner(inner)
+                                disr_val: int,
+                                n_fields: uint,
+                                name: &str) -> bool {
+        let mut write = false;
+        match self.var_stk.pop() {
+            Degenerate => {
+                write = true;
+                self.var_stk.push(Degenerate);
+            }
+            TagMatch | TagMismatch => {
+                do self.get::<int>() |t| {
+                    if disr_val == *t {
+                        write = true;
+                        self.var_stk.push(TagMatch);
+                    } else {
+                        self.var_stk.push(TagMismatch);
+                    }
+                };
+                self.bump_past::<int>();
+            }
+        }
+
+        if write {
+            self.writer.write_str(name);
+            if n_fields > 0 {
+                self.writer.write_char('(');
+            }
+        }
+        true
+    }
+    fn visit_enum_variant_field(i: uint, inner: *TyDesc) -> bool {
+        match self.var_stk.last() {
+            Degenerate | TagMatch => {
+                if i != 0 {
+                    self.writer.write_str(", ");
+                }
+                if ! self.visit_inner(inner) {
+                    return false;
+                }
+            }
+            TagMismatch => ()
+        }
+        true
     }
     fn visit_leave_enum_variant(_variant: uint,
                                 _disr_val: int,
-                                _n_fields: uint,
-                                _name: &str) -> bool { true }
+                                n_fields: uint,
+                                _name: &str) -> bool {
+        match self.var_stk.last() {
+            Degenerate | TagMatch => {
+                if n_fields > 0 {
+                    self.writer.write_char(')');
+                }
+            }
+            TagMismatch => ()
+        }
+        true
+    }
     fn visit_leave_enum(_n_variants: uint,
-                        _sz: uint, _align: uint) -> bool { true }
+                        _sz: uint, _align: uint) -> bool {
+        self.var_stk.pop();
+        true
+    }
 
     fn visit_enter_fn(_purity: uint, _proto: uint,
                       _n_inputs: uint, _retstyle: uint) -> bool { true }