about summary refs log tree commit diff
path: root/src/libstd/slice.rs
diff options
context:
space:
mode:
authorJames Miller <james@aatch.net>2014-04-16 14:29:36 +1200
committerJames Miller <james@aatch.net>2014-04-16 14:29:36 +1200
commitbe334d582435a05ea56c1ca7fcb2e512cfc51f24 (patch)
tree900da71bc36964d4cbe260b94db3d1163b74f48a /src/libstd/slice.rs
parent42b39924d87739f2dcda3e788c6e8655d310954f (diff)
downloadrust-be334d582435a05ea56c1ca7fcb2e512cfc51f24.tar.gz
rust-be334d582435a05ea56c1ca7fcb2e512cfc51f24.zip
Make Vec::clone and slice::to_owned failure-safe
Diffstat (limited to 'src/libstd/slice.rs')
-rw-r--r--src/libstd/slice.rs25
1 files changed, 15 insertions, 10 deletions
diff --git a/src/libstd/slice.rs b/src/libstd/slice.rs
index f4f97ea8c92..153e21c780c 100644
--- a/src/libstd/slice.rs
+++ b/src/libstd/slice.rs
@@ -762,18 +762,23 @@ impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
     fn to_owned(&self) -> ~[T] {
         let len = self.len();
         let mut result = with_capacity(len);
+        // Unsafe code so this can be optimised to a memcpy (or something
+        // similarly fast) when T is Copy. LLVM is easily confused, so any
+        // extra operations during the loop can prevent this optimisation
         unsafe {
-            // Unsafe code so this can be optimised to a memcpy (or something
-            // similarly fast) when T is Copy. LLVM is easily confused, so any
-            // extra operations during the loop can prevent this optimisation
-            result.set_len(len);
             let mut i = 0;
-            while i < len {
-                mem::move_val_init(
-                    result.unsafe_mut_ref(i),
-                    self.unsafe_ref(i).clone());
-                i = i + 1;
-            }
+            let p = result.as_mut_ptr();
+            // Use try_finally here otherwise the write to length
+            // inside the loop stops LLVM from optimising this.
+            try_finally(
+                &mut i, (),
+                |i, ()| while *i < len {
+                    mem::move_val_init(
+                        &mut(*p.offset(*i as int)),
+                        self.unsafe_ref(*i).clone());
+                    *i += 1;
+                },
+                |i| result.set_len(*i));
         }
         result
     }