about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2013-05-29 18:33:30 -0400
committerNiko Matsakis <niko@alum.mit.edu>2013-05-30 15:20:36 -0400
commit5209709e46ecfac2fd4db527952fe7ef96400801 (patch)
treeae09745be3c75657f375c0a8d794cc23a878a8b1 /src
parentc492a2126fddb1b844ddee05a283a92329c6c041 (diff)
downloadrust-5209709e46ecfac2fd4db527952fe7ef96400801.tar.gz
rust-5209709e46ecfac2fd4db527952fe7ef96400801.zip
Fix matching of rvalues with destructors
Fixes #4542.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/trans/_match.rs2
-rw-r--r--src/librustc/middle/trans/datum.rs25
-rw-r--r--src/test/run-pass/match-vec-rvalue.rs12
3 files changed, 38 insertions, 1 deletions
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index 6399fa5eedf..049e2162fe8 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -1701,7 +1701,7 @@ pub fn trans_match_inner(scope_cx: block,
             None
         }
     };
-    let lldiscr = discr_datum.to_ref_llval(bcx);
+    let lldiscr = discr_datum.to_zeroable_ref_llval(bcx);
     compile_submatch(bcx, matches, [lldiscr], chk);
 
     let mut arm_cxs = ~[];
diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs
index 0f325c432f4..c0403083ce1 100644
--- a/src/librustc/middle/trans/datum.rs
+++ b/src/librustc/middle/trans/datum.rs
@@ -471,6 +471,31 @@ pub impl Datum {
         }
     }
 
+    fn to_zeroable_ref_llval(&self, bcx: block) -> ValueRef {
+        /*!
+         * Returns a by-ref llvalue that can be zeroed in order to
+         * cancel cleanup. This is a kind of hokey bridge used
+         * to adapt to the match code. Please don't use it for new code.
+         */
+
+        match self.mode {
+            // All by-ref datums are zeroable, even if we *could* just
+            // cancel the cleanup.
+            ByRef(_) => self.val,
+
+            // By value datums can't be zeroed (where would you store
+            // the zero?) so we have to spill them. Add a temp cleanup
+            // for this spilled value and cancel the cleanup on this
+            // current value.
+            ByValue => {
+                let slot = self.to_ref_llval(bcx);
+                self.cancel_clean(bcx);
+                add_clean_temp_mem(bcx, slot, self.ty);
+                slot
+            }
+        }
+    }
+
     fn appropriate_mode(&self) -> DatumMode {
         /*! See the `appropriate_mode()` function */
 
diff --git a/src/test/run-pass/match-vec-rvalue.rs b/src/test/run-pass/match-vec-rvalue.rs
new file mode 100644
index 00000000000..5f68b0e9a69
--- /dev/null
+++ b/src/test/run-pass/match-vec-rvalue.rs
@@ -0,0 +1,12 @@
+// Tests that matching rvalues with drops does not crash.
+
+fn main() {
+    match ~[1, 2, 3] {
+        x => {
+            assert_eq!(x.len(), 3);
+            assert_eq!(x[0], 1);
+            assert_eq!(x[1], 2);
+            assert_eq!(x[2], 3);
+        }
+    }
+}