From d6e583ab1038ffe2706e5ecdc96a3da207f87c16 Mon Sep 17 00:00:00 2001
From: Erick Tryzelaar <erick.tryzelaar@gmail.com>
Date: Sun, 3 Mar 2013 14:49:44 -0800
Subject: [PATCH 1/9] std: remove an unnecessary copy from workcache

---
 src/libstd/workcache.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libstd/workcache.rs b/src/libstd/workcache.rs
index 1dd7bfd75db8f..c46c2d17ed0c6 100644
--- a/src/libstd/workcache.rs
+++ b/src/libstd/workcache.rs
@@ -174,7 +174,7 @@ pub impl Database {
         let k = json_encode(&(fn_name, declared_inputs));
         match self.db_cache.find(&k) {
             None => None,
-            Some(&v) => Some(json_decode(copy v))
+            Some(v) => Some(json_decode(*v))
         }
     }
 

From ac4016ff992bde67b37448200abdc84680d49d72 Mon Sep 17 00:00:00 2001
From: Erick Tryzelaar <erick.tryzelaar@gmail.com>
Date: Sun, 3 Mar 2013 07:52:06 -0800
Subject: [PATCH 2/9] rustdoc: Remove a unused variable warning

---
 src/librustdoc/config.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 21c0393f68f6f..187ddcc015261 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -262,7 +262,7 @@ fn should_find_pandoc() {
         output_format: PandocHtml,
         .. default_config(&Path("test"))
     };
-    let mock_program_output: ~fn(&str, &[~str]) -> ProgramOutput = |prog, _| {
+    let mock_program_output: ~fn(&str, &[~str]) -> ProgramOutput = |_, _| {
         ProgramOutput { status: 0, out: ~"pandoc 1.8.2.1", err: ~"" }
     };
     let result = maybe_find_pandoc(&config, None, mock_program_output);

From 431e756fd72df1c092e71f6e605e82385a9c6881 Mon Sep 17 00:00:00 2001
From: Erick Tryzelaar <erick.tryzelaar@gmail.com>
Date: Sun, 3 Mar 2013 09:01:28 -0800
Subject: [PATCH 3/9] rustdoc: change paragraphs fn to take &str

---
 src/librustdoc/desc_to_brief_pass.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/librustdoc/desc_to_brief_pass.rs b/src/librustdoc/desc_to_brief_pass.rs
index b4d990ccdd24c..963715796e65a 100644
--- a/src/librustdoc/desc_to_brief_pass.rs
+++ b/src/librustdoc/desc_to_brief_pass.rs
@@ -142,7 +142,7 @@ fn parse_desc(desc: ~str) -> Option<~str> {
 }
 
 fn first_sentence(s: ~str) -> Option<~str> {
-    let paras = paragraphs(copy s);
+    let paras = paragraphs(s);
     if !paras.is_empty() {
         let first_para = vec::head(paras);
         Some(str::replace(first_sentence_(first_para), ~"\n", ~" "))
@@ -182,7 +182,7 @@ fn first_sentence_(s: ~str) -> ~str {
     }
 }
 
-fn paragraphs(s: ~str) -> ~[~str] {
+fn paragraphs(s: &str) -> ~[~str] {
     let lines = str::lines_any(s);
     let mut whitespace_lines = 0;
     let mut accum = ~"";

From 359bb3e10bb022aabc5bfc60e48d3dfffc2ee62c Mon Sep 17 00:00:00 2001
From: Erick Tryzelaar <erick.tryzelaar@gmail.com>
Date: Sat, 2 Mar 2013 21:49:50 -0800
Subject: [PATCH 4/9] core: convert vec::{head,head_opt} to return references

---
 src/libcore/vec.rs                   | 52 +++++++++++++++++++++++-----
 src/librust/rust.rc                  | 12 ++++---
 src/librustdoc/config.rs             |  2 +-
 src/librustdoc/desc_to_brief_pass.rs | 24 ++++++-------
 src/librustdoc/unindent_pass.rs      |  2 +-
 src/test/run-pass/zip-same-length.rs |  7 ++--
 6 files changed, 68 insertions(+), 31 deletions(-)

diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index ab5f04ace79c0..20aadd79d12ef 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -211,7 +211,16 @@ pub pure fn build_sized_opt<A>(size: Option<uint>,
 // Accessors
 
 /// Returns the first element of a vector
-pub pure fn head<T:Copy>(v: &[const T]) -> T { v[0] }
+pub pure fn head<T>(v: &r/[T]) -> &r/T {
+    if v.len() == 0 { fail!(~"last_unsafe: empty vector") }
+    &v[0]
+}
+
+/// Returns `Some(x)` where `x` is the first element of the slice `v`,
+/// or `None` if the vector is empty.
+pub pure fn head_opt<T>(v: &r/[T]) -> Option<&r/T> {
+    if v.len() == 0 { None } else { Some(&v[0]) }
+}
 
 /// Returns a vector containing all but the first element of a slice
 pub pure fn tail<T:Copy>(v: &[const T]) -> ~[T] {
@@ -1692,7 +1701,6 @@ impl<T> Container for &[const T] {
 }
 
 pub trait CopyableVector<T> {
-    pure fn head(&self) -> T;
     pure fn init(&self) -> ~[T];
     pure fn last(&self) -> T;
     pure fn slice(&self, start: uint, end: uint) -> ~[T];
@@ -1701,10 +1709,6 @@ pub trait CopyableVector<T> {
 
 /// Extension methods for vectors
 impl<T:Copy> CopyableVector<T> for &[const T] {
-    /// Returns the first element of a vector
-    #[inline]
-    pure fn head(&self) -> T { head(*self) }
-
     /// Returns all but the last elemnt of a vector
     #[inline]
     pure fn init(&self) -> ~[T] { init(*self) }
@@ -1726,7 +1730,9 @@ impl<T:Copy> CopyableVector<T> for &[const T] {
 
 pub trait ImmutableVector<T> {
     pure fn view(&self, start: uint, end: uint) -> &self/[T];
-    pure fn foldr<U:Copy>(&self, z: U, p: fn(t: &T, u: U) -> U) -> U;
+    pure fn head(&self) -> &self/T;
+    pure fn head_opt(&self) -> Option<&self/T>;
+    pure fn foldr<U: Copy>(&self, z: U, p: fn(t: &T, u: U) -> U) -> U;
     pure fn map<U>(&self, f: fn(t: &T) -> U) -> ~[U];
     pure fn mapi<U>(&self, f: fn(uint, t: &T) -> U) -> ~[U];
     fn map_r<U>(&self, f: fn(x: &T) -> U) -> ~[U];
@@ -1743,6 +1749,14 @@ impl<T> ImmutableVector<T> for &[T] {
         slice(*self, start, end)
     }
 
+    /// Returns the first element of a vector, failing if the vector is empty.
+    #[inline]
+    pure fn head(&self) -> &self/T { head(*self) }
+
+    /// Returns the first element of a vector
+    #[inline]
+    pure fn head_opt(&self) -> Option<&self/T> { head_opt(*self) }
+
     /// Reduce a vector from right to left
     #[inline]
     pure fn foldr<U:Copy>(&self, z: U, p: fn(t: &T, u: U) -> U) -> U {
@@ -2570,8 +2584,28 @@ mod tests {
 
     #[test]
     fn test_head() {
-        let a = ~[11, 12];
-        assert (head(a) == 11);
+        let mut a = ~[11];
+        assert a.head() == &11;
+        a = ~[11, 12];
+        assert a.head() == &11;
+    }
+
+    #[test]
+    #[should_fail]
+    #[ignore(cfg(windows))]
+    fn test_head_empty() {
+        let a: ~[int] = ~[];
+        a.head();
+    }
+
+    #[test]
+    fn test_head_opt() {
+        let mut a = ~[];
+        assert a.head_opt() == None;
+        a = ~[11];
+        assert a.head_opt().unwrap() == &11;
+        a = ~[11, 12];
+        assert a.head_opt().unwrap() == &11;
     }
 
     #[test]
diff --git a/src/librust/rust.rc b/src/librust/rust.rc
index 37e0f874b40dc..235ed6412a356 100644
--- a/src/librust/rust.rc
+++ b/src/librust/rust.rc
@@ -130,7 +130,7 @@ fn cmd_help(args: &[~str]) -> ValidUsage {
                     UsgExec(commandline) => {
                         let words = str::words(commandline);
                         let (prog, args) = (words.head(), words.tail());
-                        run::run_program(prog, args);
+                        run::run_program(*prog, args);
                     }
                 }
                 Valid
@@ -186,7 +186,10 @@ fn do_command(command: &Command, args: &[~str]) -> ValidUsage {
         Exec(commandline) => {
             let words = str::words(commandline);
             let (prog, prog_args) = (words.head(), words.tail());
-            let exitstatus = run::run_program(prog, prog_args + args);
+            let exitstatus = run::run_program(
+                *prog,
+                vec::append(vec::from_slice(prog_args), args)
+            );
             os::set_exit_status(exitstatus);
             Valid
         }
@@ -221,11 +224,12 @@ fn usage() {
 }
 
 pub fn main() {
-    let args = os::args().tail();
+    let os_args = os::args();
+    let args = os_args.tail();
 
     if !args.is_empty() {
         for commands.each |command| {
-            if command.cmd == args.head() {
+            if command.cmd == *args.head() {
                 let result = do_command(command, args.tail());
                 if result.is_valid() { return; }
             }
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 187ddcc015261..58316110b64ed 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -132,7 +132,7 @@ pub fn parse_config_(
     match getopts::getopts(args, opts) {
         result::Ok(matches) => {
             if matches.free.len() == 1 {
-                let input_crate = Path(vec::head(matches.free));
+                let input_crate = Path(copy *matches.free.head());
                 config_from_opts(&input_crate, &matches, program_output)
             } else if matches.free.is_empty() {
                 result::Err(~"no crates specified")
diff --git a/src/librustdoc/desc_to_brief_pass.rs b/src/librustdoc/desc_to_brief_pass.rs
index 963715796e65a..3a4cd9e1379f9 100644
--- a/src/librustdoc/desc_to_brief_pass.rs
+++ b/src/librustdoc/desc_to_brief_pass.rs
@@ -144,14 +144,14 @@ fn parse_desc(desc: ~str) -> Option<~str> {
 fn first_sentence(s: ~str) -> Option<~str> {
     let paras = paragraphs(s);
     if !paras.is_empty() {
-        let first_para = vec::head(paras);
-        Some(str::replace(first_sentence_(first_para), ~"\n", ~" "))
+        let first_para = paras.head();
+        Some(str::replace(first_sentence_(*first_para), ~"\n", ~" "))
     } else {
         None
     }
 }
 
-fn first_sentence_(s: ~str) -> ~str {
+fn first_sentence_(s: &str) -> ~str {
     let mut dotcount = 0;
     // The index of the character following a single dot. This allows
     // Things like [0..1) to appear in the brief description
@@ -169,16 +169,16 @@ fn first_sentence_(s: ~str) -> ~str {
         }
     };
     match idx {
-      Some(idx) if idx > 2u => {
-        str::slice(s, 0u, idx - 1u)
-      }
-      _ => {
-        if str::ends_with(s, ~".") {
-            str::slice(s, 0u, str::len(s))
-        } else {
-            copy s
+        Some(idx) if idx > 2u => {
+            str::from_slice(str::view(s, 0, idx - 1))
+        }
+        _ => {
+            if str::ends_with(s, ~".") {
+                str::from_slice(s)
+            } else {
+                str::from_slice(s)
+            }
         }
-      }
     }
 }
 
diff --git a/src/librustdoc/unindent_pass.rs b/src/librustdoc/unindent_pass.rs
index d5b9756faa5e2..5fafcf392bec6 100644
--- a/src/librustdoc/unindent_pass.rs
+++ b/src/librustdoc/unindent_pass.rs
@@ -78,7 +78,7 @@ fn unindent(s: &str) -> ~str {
     };
 
     if !lines.is_empty() {
-        let unindented = ~[str::trim(vec::head(lines))]
+        let unindented = ~[lines.head().trim()]
             + do vec::tail(lines).map |line| {
             if str::is_whitespace(*line) {
                 copy *line
diff --git a/src/test/run-pass/zip-same-length.rs b/src/test/run-pass/zip-same-length.rs
index 1ade9e8246fdd..29b58cd643115 100644
--- a/src/test/run-pass/zip-same-length.rs
+++ b/src/test/run-pass/zip-same-length.rs
@@ -10,7 +10,6 @@
 
 // In this case, the code should compile and should
 // succeed at runtime
-use core::vec::{head, last, same_length, zip};
 
 fn enum_chars(start: u8, end: u8) -> ~[char] {
     assert start < end;
@@ -33,8 +32,8 @@ pub fn main() {
     let chars = enum_chars(a, j);
     let ints = enum_uints(k, l);
 
-    let ps = zip(chars, ints);
+    let ps = vec::zip(chars, ints);
 
-    assert (head(ps) == ('a', 1u));
-    assert (last(ps) == (j as char, 10u));
+    assert (ps.head() == &('a', 1u));
+    assert (ps.last() == (j as char, 10u));
 }

From 5ae06ae9dea2f1dac157193b702f640e2216a5a9 Mon Sep 17 00:00:00 2001
From: Erick Tryzelaar <erick.tryzelaar@gmail.com>
Date: Sun, 3 Mar 2013 07:22:40 -0800
Subject: [PATCH 5/9] core: convert vec::{tail,tailn} to return references

---
 src/libcore/vec.rs                 | 57 +++++++++++++++++---------
 src/librustc/middle/check_match.rs | 65 ++++++++++++++++++------------
 src/librustc/middle/trans/cabi.rs  |  8 ++--
 src/librustdoc/unindent_pass.rs    |  2 +-
 4 files changed, 84 insertions(+), 48 deletions(-)

diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 20aadd79d12ef..98316066fd176 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -223,17 +223,10 @@ pub pure fn head_opt<T>(v: &r/[T]) -> Option<&r/T> {
 }
 
 /// Returns a vector containing all but the first element of a slice
-pub pure fn tail<T:Copy>(v: &[const T]) -> ~[T] {
-    slice(v, 1u, len(v)).to_vec()
-}
+pub pure fn tail<T>(v: &r/[T]) -> &r/[T] { slice(v, 1, v.len()) }
 
-/**
- * Returns a vector containing all but the first `n` \
- * elements of a slice
- */
-pub pure fn tailn<T:Copy>(v: &[const T], n: uint) -> ~[T] {
-    slice(v, n, len(v)).to_vec()
-}
+/// Returns a vector containing all but the first `n` elements of a slice
+pub pure fn tailn<T>(v: &r/[T], n: uint) -> &r/[T] { slice(v, n, v.len()) }
 
 /// Returns a vector containing all but the last element of a slice
 pub pure fn init<T:Copy>(v: &[const T]) -> ~[T] {
@@ -1704,7 +1697,6 @@ pub trait CopyableVector<T> {
     pure fn init(&self) -> ~[T];
     pure fn last(&self) -> T;
     pure fn slice(&self, start: uint, end: uint) -> ~[T];
-    pure fn tail(&self) -> ~[T];
 }
 
 /// Extension methods for vectors
@@ -1722,16 +1714,14 @@ impl<T:Copy> CopyableVector<T> for &[const T] {
     pure fn slice(&self, start: uint, end: uint) -> ~[T] {
         slice(*self, start, end).to_vec()
     }
-
-    /// Returns all but the first element of a vector
-    #[inline]
-    pure fn tail(&self) -> ~[T] { tail(*self) }
 }
 
 pub trait ImmutableVector<T> {
     pure fn view(&self, start: uint, end: uint) -> &self/[T];
     pure fn head(&self) -> &self/T;
     pure fn head_opt(&self) -> Option<&self/T>;
+    pure fn tail(&self) -> &self/[T];
+    pure fn tailn(&self, n: uint) -> &self/[T];
     pure fn foldr<U: Copy>(&self, z: U, p: fn(t: &T, u: U) -> U) -> U;
     pure fn map<U>(&self, f: fn(t: &T) -> U) -> ~[U];
     pure fn mapi<U>(&self, f: fn(uint, t: &T) -> U) -> ~[U];
@@ -1757,6 +1747,14 @@ impl<T> ImmutableVector<T> for &[T] {
     #[inline]
     pure fn head_opt(&self) -> Option<&self/T> { head_opt(*self) }
 
+    /// Returns all but the first element of a vector
+    #[inline]
+    pure fn tail(&self) -> &self/[T] { tail(*self) }
+
+    /// Returns all but the first `n' elements of a vector
+    #[inline]
+    pure fn tailn(&self, n: uint) -> &self/[T] { tailn(*self, n) }
+
     /// Reduce a vector from right to left
     #[inline]
     pure fn foldr<U:Copy>(&self, z: U, p: fn(t: &T, u: U) -> U) -> U {
@@ -2611,10 +2609,33 @@ mod tests {
     #[test]
     fn test_tail() {
         let mut a = ~[11];
-        assert (tail(a) == ~[]);
-
+        assert a.tail() == &[];
         a = ~[11, 12];
-        assert (tail(a) == ~[12]);
+        assert a.tail() == &[12];
+    }
+
+    #[test]
+    #[should_fail]
+    #[ignore(cfg(windows))]
+    fn test_tail_empty() {
+        let a: ~[int] = ~[];
+        a.tail();
+    }
+
+    #[test]
+    fn test_tailn() {
+        let mut a = ~[11, 12, 13];
+        assert a.tailn(0) == &[11, 12, 13];
+        a = ~[11, 12, 13];
+        assert a.tailn(2) == &[13];
+    }
+
+    #[test]
+    #[should_fail]
+    #[ignore(cfg(windows))]
+    fn test_tailn_empty() {
+        let a: ~[int] = ~[];
+        a.tailn(2);
     }
 
     #[test]
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 51cb305ab028e..7dd31374fc677 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -265,7 +265,7 @@ pub fn is_useful(cx: @MatchCheckCtxt, +m: matrix, +v: &[@pat]) -> useful {
           Some(ref ctor) => {
             match is_useful(cx,
                             vec::filter_map(m, |r| default(cx, r)),
-                            vec::tail(v)) {
+                            v.tail()) {
               useful_ => useful(left_ty, (/*bad*/copy *ctor)),
               ref u => (/*bad*/copy *u)
             }
@@ -281,7 +281,7 @@ pub fn is_useful(cx: @MatchCheckCtxt, +m: matrix, +v: &[@pat]) -> useful {
 
 pub fn is_useful_specialized(cx: @MatchCheckCtxt,
                              m: matrix,
-                             +v: &[@pat],
+                             v: &[@pat],
                              +ctor: ctor,
                              arity: uint,
                              lty: ty::t)
@@ -475,7 +475,7 @@ pub fn wild() -> @pat {
 }
 
 pub fn specialize(cx: @MatchCheckCtxt,
-                  +r: &[@pat],
+                  r: &[@pat],
                   ctor_id: ctor,
                   arity: uint,
                   left_ty: ty::t)
@@ -485,13 +485,17 @@ pub fn specialize(cx: @MatchCheckCtxt,
     match r0 {
         pat{id: pat_id, node: n, span: pat_span} =>
             match n {
-            pat_wild => Some(vec::append(vec::from_elem(arity, wild()),
-                                         vec::tail(r))),
+            pat_wild => {
+                Some(vec::append(vec::from_elem(arity, wild()), r.tail()))
+            }
             pat_ident(_, _, _) => {
                 match cx.tcx.def_map.find(&pat_id) {
                     Some(def_variant(_, id)) => {
-                        if variant(id) == ctor_id { Some(vec::tail(r)) }
-                        else { None }
+                        if variant(id) == ctor_id {
+                            Some(vec::from_slice(r.tail()))
+                        } else {
+                            None
+                        }
                     }
                     Some(def_const(did)) => {
                         let const_expr =
@@ -506,10 +510,20 @@ pub fn specialize(cx: @MatchCheckCtxt,
                             single => true,
                             _ => fail!(~"type error")
                         };
-                        if match_ { Some(vec::tail(r)) } else { None }
+                        if match_ {
+                            Some(vec::from_slice(r.tail()))
+                        } else {
+                            None
+                        }
+                    }
+                    _ => {
+                        Some(
+                            vec::append(
+                                vec::from_elem(arity, wild()),
+                                r.tail()
+                            )
+                        )
                     }
-                    _ => Some(vec::append(vec::from_elem(arity, wild()),
-                                          vec::tail(r)))
                 }
             }
             pat_enum(_, args) => {
@@ -519,7 +533,7 @@ pub fn specialize(cx: @MatchCheckCtxt,
                             Some(args) => args,
                             None => vec::from_elem(arity, wild())
                         };
-                        Some(vec::append(args, vec::tail(r)))
+                        Some(vec::append(args, vec::from_slice(r.tail())))
                     }
                     def_variant(_, _) => None,
                     def_struct(*) => {
@@ -529,7 +543,7 @@ pub fn specialize(cx: @MatchCheckCtxt,
                             Some(args) => new_args = args,
                             None => new_args = vec::from_elem(arity, wild())
                         }
-                        Some(vec::append(new_args, vec::tail(r)))
+                        Some(vec::append(new_args, vec::from_slice(r.tail())))
                     }
                     _ => None
                 }
@@ -545,7 +559,7 @@ pub fn specialize(cx: @MatchCheckCtxt,
                         _ => wild()
                     }
                 });
-                Some(vec::append(args, vec::tail(r)))
+                Some(vec::append(args, vec::from_slice(r.tail())))
             }
             pat_struct(_, ref flds, _) => {
                 // Is this a struct or an enum variant?
@@ -560,7 +574,7 @@ pub fn specialize(cx: @MatchCheckCtxt,
                                     _ => wild()
                                 }
                             });
-                            Some(vec::append(args, vec::tail(r)))
+                            Some(vec::append(args, vec::from_slice(r.tail())))
                         } else {
                             None
                         }
@@ -587,13 +601,14 @@ pub fn specialize(cx: @MatchCheckCtxt,
                                 _ => wild()
                             }
                         });
-                        Some(vec::append(args, vec::tail(r)))
+                        Some(vec::append(args, vec::from_slice(r.tail())))
                     }
                 }
             }
-            pat_tup(args) => Some(vec::append(args, vec::tail(r))),
-            pat_box(a) | pat_uniq(a) | pat_region(a) =>
-                Some(vec::append(~[a], vec::tail(r))),
+            pat_tup(args) => Some(vec::append(args, r.tail())),
+            pat_box(a) | pat_uniq(a) | pat_region(a) => {
+                Some(vec::append(~[a], r.tail()))
+            }
             pat_lit(expr) => {
                 let e_v = eval_const_expr(cx.tcx, expr);
                 let match_ = match ctor_id {
@@ -605,21 +620,21 @@ pub fn specialize(cx: @MatchCheckCtxt,
                     single => true,
                     _ => fail!(~"type error")
                 };
-                if match_ { Some(vec::tail(r)) } else { None }
+                if match_ { Some(vec::from_slice(r.tail())) } else { None }
             }
             pat_range(lo, hi) => {
                 let (c_lo, c_hi) = match ctor_id {
                     val(ref v) => ((/*bad*/copy *v), (/*bad*/copy *v)),
                     range(ref lo, ref hi) =>
                         ((/*bad*/copy *lo), (/*bad*/copy *hi)),
-                    single => return Some(vec::tail(r)),
+                    single => return Some(vec::from_slice(r.tail())),
                     _ => fail!(~"type error")
                 };
                 let v_lo = eval_const_expr(cx.tcx, lo),
                 v_hi = eval_const_expr(cx.tcx, hi);
                 let match_ = compare_const_vals(c_lo, v_lo) >= 0 &&
                     compare_const_vals(c_hi, v_hi) <= 0;
-          if match_ { Some(vec::tail(r)) } else { None }
+          if match_ { Some(vec::from_slice(r.tail())) } else { None }
       }
             pat_vec(elems, tail) => {
                 match ctor_id {
@@ -630,10 +645,10 @@ pub fn specialize(cx: @MatchCheckCtxt,
                                 vec::append(elems, vec::from_elem(
                                     arity - num_elements, wild()
                                 )),
-                                vec::tail(r)
+                                vec::from_slice(r.tail())
                             ))
                         } else if num_elements == arity {
-                            Some(vec::append(elems, vec::tail(r)))
+                            Some(vec::append(elems, r.tail()))
                         } else {
                             None
                         }
@@ -645,8 +660,8 @@ pub fn specialize(cx: @MatchCheckCtxt,
     }
 }
 
-pub fn default(cx: @MatchCheckCtxt, r: ~[@pat]) -> Option<~[@pat]> {
-    if is_wild(cx, r[0]) { Some(vec::tail(r)) }
+pub fn default(cx: @MatchCheckCtxt, r: &[@pat]) -> Option<~[@pat]> {
+    if is_wild(cx, r[0]) { Some(vec::from_slice(r.tail())) }
     else { None }
 }
 
diff --git a/src/librustc/middle/trans/cabi.rs b/src/librustc/middle/trans/cabi.rs
index bbc19cf86eaac..1d7314f751870 100644
--- a/src/librustc/middle/trans/cabi.rs
+++ b/src/librustc/middle/trans/cabi.rs
@@ -71,8 +71,8 @@ pub impl FnType {
             let llretptr = GEPi(bcx, llargbundle, [0u, n]);
             let llretloc = Load(bcx, llretptr);
                 llargvals = ~[llretloc];
-                atys = vec::tail(atys);
-                attrs = vec::tail(attrs);
+                atys = vec::from_slice(atys.tail());
+                attrs = vec::from_slice(attrs.tail());
         }
 
         while i < n {
@@ -131,8 +131,8 @@ pub impl FnType {
         let mut attrs = /*bad*/copy self.attrs;
         let mut j = 0u;
         let llretptr = if self.sret {
-            atys = vec::tail(atys);
-            attrs = vec::tail(attrs);
+            atys = vec::from_slice(atys.tail());
+            attrs = vec::from_slice(attrs.tail());
             j = 1u;
             get_param(llwrapfn, 0u)
         } else if self.ret_ty.cast {
diff --git a/src/librustdoc/unindent_pass.rs b/src/librustdoc/unindent_pass.rs
index 5fafcf392bec6..06595a23d9612 100644
--- a/src/librustdoc/unindent_pass.rs
+++ b/src/librustdoc/unindent_pass.rs
@@ -79,7 +79,7 @@ fn unindent(s: &str) -> ~str {
 
     if !lines.is_empty() {
         let unindented = ~[lines.head().trim()]
-            + do vec::tail(lines).map |line| {
+            + do lines.tail().map |line| {
             if str::is_whitespace(*line) {
                 copy *line
             } else {

From d60747a24839c50165b0e2ea35592a7cb008f69b Mon Sep 17 00:00:00 2001
From: Erick Tryzelaar <erick.tryzelaar@gmail.com>
Date: Sun, 3 Mar 2013 08:06:31 -0800
Subject: [PATCH 6/9] core: convert vec::{init,initn} to return references

---
 src/libcore/vec.rs               | 70 ++++++++++++++++++++++----------
 src/librustc/metadata/decoder.rs |  8 ++--
 src/librustc/middle/ty.rs        |  2 +-
 3 files changed, 54 insertions(+), 26 deletions(-)

diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 98316066fd176..2884d44861072 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -229,9 +229,11 @@ pub pure fn tail<T>(v: &r/[T]) -> &r/[T] { slice(v, 1, v.len()) }
 pub pure fn tailn<T>(v: &r/[T], n: uint) -> &r/[T] { slice(v, n, v.len()) }
 
 /// Returns a vector containing all but the last element of a slice
-pub pure fn init<T:Copy>(v: &[const T]) -> ~[T] {
-    assert len(v) != 0u;
-    slice(v, 0u, len(v) - 1u).to_vec()
+pub pure fn init<T>(v: &r/[T]) -> &r/[T] { slice(v, 0, v.len() - 1) }
+
+/// Returns a vector containing all but the last `n' elements of a slice
+pub pure fn initn<T>(v: &r/[T], n: uint) -> &r/[T] {
+    slice(v, 0, v.len() - n)
 }
 
 /// Returns the last element of the slice `v`, failing if the slice is empty.
@@ -1694,17 +1696,12 @@ impl<T> Container for &[const T] {
 }
 
 pub trait CopyableVector<T> {
-    pure fn init(&self) -> ~[T];
     pure fn last(&self) -> T;
     pure fn slice(&self, start: uint, end: uint) -> ~[T];
 }
 
 /// Extension methods for vectors
-impl<T:Copy> CopyableVector<T> for &[const T] {
-    /// Returns all but the last elemnt of a vector
-    #[inline]
-    pure fn init(&self) -> ~[T] { init(*self) }
-
+impl<T: Copy> CopyableVector<T> for &[const T] {
     /// Returns the last element of a `v`, failing if the vector is empty.
     #[inline]
     pure fn last(&self) -> T { last(*self) }
@@ -1722,6 +1719,8 @@ pub trait ImmutableVector<T> {
     pure fn head_opt(&self) -> Option<&self/T>;
     pure fn tail(&self) -> &self/[T];
     pure fn tailn(&self, n: uint) -> &self/[T];
+    pure fn init(&self) -> &self/[T];
+    pure fn initn(&self, n: uint) -> &self/[T];
     pure fn foldr<U: Copy>(&self, z: U, p: fn(t: &T, u: U) -> U) -> U;
     pure fn map<U>(&self, f: fn(t: &T) -> U) -> ~[U];
     pure fn mapi<U>(&self, f: fn(uint, t: &T) -> U) -> ~[U];
@@ -1755,6 +1754,14 @@ impl<T> ImmutableVector<T> for &[T] {
     #[inline]
     pure fn tailn(&self, n: uint) -> &self/[T] { tailn(*self, n) }
 
+    /// Returns all but the last elemnt of a vector
+    #[inline]
+    pure fn init(&self) -> &self/[T] { init(*self) }
+
+    /// Returns all but the last `n' elemnts of a vector
+    #[inline]
+    pure fn initn(&self, n: uint) -> &self/[T] { initn(*self, n) }
+
     /// Reduce a vector from right to left
     #[inline]
     pure fn foldr<U:Copy>(&self, z: U, p: fn(t: &T, u: U) -> U) -> U {
@@ -2638,6 +2645,38 @@ mod tests {
         a.tailn(2);
     }
 
+    #[test]
+    fn test_init() {
+        let mut a = ~[11];
+        assert a.init() == &[];
+        a = ~[11, 12];
+        assert a.init() == &[11];
+    }
+
+    #[init]
+    #[should_fail]
+    #[ignore(cfg(windows))]
+    fn test_init_empty() {
+        let a: ~[int] = ~[];
+        a.init();
+    }
+
+    #[test]
+    fn test_initn() {
+        let mut a = ~[11, 12, 13];
+        assert a.initn(0) == &[11, 12, 13];
+        a = ~[11, 12, 13];
+        assert a.initn(2) == &[11];
+    }
+
+    #[init]
+    #[should_fail]
+    #[ignore(cfg(windows))]
+    fn test_initn_empty() {
+        let a: ~[int] = ~[];
+        a.initn(2);
+    }
+
     #[test]
     fn test_last() {
         let mut n = last_opt(~[]);
@@ -3317,12 +3356,6 @@ mod tests {
         assert (v2[1] == 10);
     }
 
-    #[test]
-    fn test_init() {
-        let v = init(~[1, 2, 3]);
-        assert v == ~[1, 2];
-    }
-
     #[test]
     fn test_split() {
         fn f(x: &int) -> bool { *x == 3 }
@@ -3387,13 +3420,6 @@ mod tests {
                (~[], ~[1, 2, 3]);
     }
 
-    #[test]
-    #[should_fail]
-    #[ignore(cfg(windows))]
-    fn test_init_empty() {
-        init::<int>(~[]);
-    }
-
     #[test]
     fn test_concat() {
         assert concat(~[~[1], ~[2,3]]) == ~[1, 2, 3];
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index aa18c1eb450bd..0bf1fc3870449 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -558,7 +558,10 @@ pub fn maybe_get_item_ast(intr: @ident_interner, cdata: cmd, tcx: ty::ctxt,
                        -> csearch::found_ast {
     debug!("Looking up item: %d", id);
     let item_doc = lookup_item(id, cdata.data);
-    let path = vec::init(item_path(intr, item_doc));
+    let path = {
+        let item_path = item_path(intr, item_doc);
+        vec::from_slice(item_path.init())
+    };
     match decode_inlined_item(cdata, tcx, path, item_doc) {
       Some(ref ii) => csearch::found((/*bad*/copy *ii)),
       None => {
@@ -566,8 +569,7 @@ pub fn maybe_get_item_ast(intr: @ident_interner, cdata: cmd, tcx: ty::ctxt,
           Some(did) => {
             let did = translate_def_id(cdata, did);
             let parent_item = lookup_item(did.node, cdata.data);
-            match decode_inlined_item(cdata, tcx, path,
-                                               parent_item) {
+            match decode_inlined_item(cdata, tcx, path, parent_item) {
               Some(ref ii) => csearch::found_parent(did, (/*bad*/copy *ii)),
               None => csearch::not_found
             }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 644b2c5145441..12a2011ad2560 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3815,7 +3815,7 @@ pub fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path {
           }
 
           ast_map::node_variant(ref variant, _, path) => {
-            vec::append_one(vec::init(*path),
+            vec::append_one(vec::from_slice(vec::init(*path)),
                             ast_map::path_name((*variant).node.name))
           }
 

From 8f263dd0238ff85943a794bd3214ffa64b764a64 Mon Sep 17 00:00:00 2001
From: Erick Tryzelaar <erick.tryzelaar@gmail.com>
Date: Sun, 3 Mar 2013 08:50:20 -0800
Subject: [PATCH 7/9] rustc: remove some copies

---
 src/librustc/metadata/creader.rs   |  2 +-
 src/librustc/metadata/loader.rs    | 13 +++++++------
 src/librustc/middle/astencode.rs   |  2 +-
 src/librustc/middle/check_match.rs |  6 +++---
 4 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index c7c81d0b1c06c..0776611342a3b 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -65,7 +65,7 @@ struct cache_entry {
     metas: @~[@ast::meta_item]
 }
 
-fn dump_crates(+crate_cache: @mut ~[cache_entry]) {
+fn dump_crates(crate_cache: @mut ~[cache_entry]) {
     debug!("resolved crates:");
     for crate_cache.each |entry| {
         debug!("cnum: %?", entry.cnum);
diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs
index da7f3635c0e24..0fdea7abebf33 100644
--- a/src/librustc/metadata/loader.rs
+++ b/src/librustc/metadata/loader.rs
@@ -84,11 +84,12 @@ fn libname(cx: Context) -> (~str, ~str) {
     (str::from_slice(dll_prefix), str::from_slice(dll_suffix))
 }
 
-fn find_library_crate_aux(cx: Context,
-                          (prefix, suffix): (~str, ~str),
-                          filesearch: filesearch::FileSearch) ->
-   Option<(~str, @~[u8])> {
-    let crate_name = crate_name_from_metas(/*bad*/copy cx.metas);
+fn find_library_crate_aux(
+    cx: Context,
+    (prefix, suffix): (~str, ~str),
+    filesearch: filesearch::FileSearch
+) -> Option<(~str, @~[u8])> {
+    let crate_name = crate_name_from_metas(cx.metas);
     let prefix: ~str = prefix + *crate_name + ~"-";
     let suffix: ~str = /*bad*/copy suffix;
 
@@ -140,7 +141,7 @@ fn find_library_crate_aux(cx: Context,
     }
 }
 
-pub fn crate_name_from_metas(+metas: &[@ast::meta_item]) -> @~str {
+pub fn crate_name_from_metas(metas: &[@ast::meta_item]) -> @~str {
     let name_items = attr::find_meta_items_by_name(metas, ~"name");
     match vec::last_opt(name_items) {
         Some(i) => {
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 016daf3ac9f5f..cf88a0eb90240 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -105,7 +105,7 @@ pub fn encode_inlined_item(ecx: @e::EncodeContext,
 pub fn decode_inlined_item(cdata: @cstore::crate_metadata,
                            tcx: ty::ctxt,
                            maps: Maps,
-                           +path: ast_map::path,
+                           path: ast_map::path,
                            par_doc: ebml::Doc)
                         -> Option<ast::inlined_item> {
     let dcx = @DecodeContext {
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 7dd31374fc677..f43fd75864903 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -71,7 +71,7 @@ pub fn check_expr(cx: @MatchCheckCtxt, ex: @expr, &&s: (), v: visit::vt<()>) {
                                             arm.pats);
         }
 
-        check_arms(cx, (/*bad*/copy *arms));
+        check_arms(cx, *arms);
         /* Check for exhaustiveness */
          // Check for empty enum, because is_useful only works on inhabited
          // types.
@@ -108,12 +108,12 @@ pub fn check_expr(cx: @MatchCheckCtxt, ex: @expr, &&s: (), v: visit::vt<()>) {
 }
 
 // Check for unreachable patterns
-pub fn check_arms(cx: @MatchCheckCtxt, arms: ~[arm]) {
+pub fn check_arms(cx: @MatchCheckCtxt, arms: &[arm]) {
     let mut seen = ~[];
     for arms.each |arm| {
         for arm.pats.each |pat| {
             let v = ~[*pat];
-            match is_useful(cx, copy seen, v) {
+            match is_useful(cx, &seen, v) {
               not_useful => {
                 cx.tcx.sess.span_err(pat.span, ~"unreachable pattern");
               }

From a18bf8c67d99385ce4db6083ed8d4368c5b6ccfe Mon Sep 17 00:00:00 2001
From: Erick Tryzelaar <erick.tryzelaar@gmail.com>
Date: Sun, 3 Mar 2013 11:44:11 -0800
Subject: [PATCH 8/9] rustc: minor code cleanup

---
 src/librustc/metadata/loader.rs    |  2 +-
 src/librustc/middle/check_match.rs | 16 ++++++++--------
 src/librustc/middle/pat_util.rs    |  2 +-
 src/librustdoc/config.rs           | 12 ++++++------
 4 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs
index 0fdea7abebf33..76080ece3d869 100644
--- a/src/librustc/metadata/loader.rs
+++ b/src/librustc/metadata/loader.rs
@@ -97,7 +97,7 @@ fn find_library_crate_aux(
     filesearch::search(filesearch, |path| {
         debug!("inspecting file %s", path.to_str());
         let f: ~str = path.filename().get();
-        if !(str::starts_with(f, prefix) && str::ends_with(f, suffix)) {
+        if !(f.starts_with(prefix) && f.ends_with(suffix)) {
             debug!("skipping %s, doesn't look like %s*%s", path.to_str(),
                    prefix, suffix);
             option::None::<()>
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index f43fd75864903..f9f655d50218f 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -133,7 +133,7 @@ pub fn raw_pat(p: @pat) -> @pat {
 
 pub fn check_exhaustive(cx: @MatchCheckCtxt, sp: span, pats: ~[@pat]) {
     assert(!pats.is_empty());
-    let ext = match is_useful(cx, vec::map(pats, |p| ~[*p]), ~[wild()]) {
+    let ext = match is_useful(cx, &pats.map(|p| ~[*p]), ~[wild()]) {
         not_useful => {
             // This is good, wildcard pattern isn't reachable
             return;
@@ -165,7 +165,7 @@ pub fn check_exhaustive(cx: @MatchCheckCtxt, sp: span, pats: ~[@pat]) {
                 ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
                     match *ctor {
                         vec(n) => Some(@fmt!("vectors of length %u", n)),
-                    _ => None
+                        _ => None
                     }
                 }
                 _ => None
@@ -205,10 +205,10 @@ pub enum ctor {
 
 // Note: is_useful doesn't work on empty types, as the paper notes.
 // So it assumes that v is non-empty.
-pub fn is_useful(cx: @MatchCheckCtxt, +m: matrix, +v: &[@pat]) -> useful {
+pub fn is_useful(cx: @MatchCheckCtxt, m: &matrix, v: &[@pat]) -> useful {
     if m.len() == 0u { return useful_; }
     if m[0].len() == 0u { return not_useful; }
-    let real_pat = match vec::find(m, |r| r[0].id != 0) {
+    let real_pat = match m.find(|r| r[0].id != 0) {
       Some(r) => r[0], None => v[0]
     };
     let left_ty = if real_pat.id == 0 { ty::mk_nil(cx.tcx) }
@@ -264,7 +264,7 @@ pub fn is_useful(cx: @MatchCheckCtxt, +m: matrix, +v: &[@pat]) -> useful {
           }
           Some(ref ctor) => {
             match is_useful(cx,
-                            vec::filter_map(m, |r| default(cx, r)),
+                            &m.filter_mapped(|r| default(cx, *r)),
                             v.tail()) {
               useful_ => useful(left_ty, (/*bad*/copy *ctor)),
               ref u => (/*bad*/copy *u)
@@ -280,7 +280,7 @@ pub fn is_useful(cx: @MatchCheckCtxt, +m: matrix, +v: &[@pat]) -> useful {
 }
 
 pub fn is_useful_specialized(cx: @MatchCheckCtxt,
-                             m: matrix,
+                             m: &matrix,
                              v: &[@pat],
                              +ctor: ctor,
                              arity: uint,
@@ -288,7 +288,7 @@ pub fn is_useful_specialized(cx: @MatchCheckCtxt,
                           -> useful {
     let ms = m.filter_mapped(|r| specialize(cx, *r, ctor, arity, lty));
     let could_be_useful = is_useful(
-        cx, ms, specialize(cx, v, ctor, arity, lty).get());
+        cx, &ms, specialize(cx, v, ctor, arity, lty).get());
     match could_be_useful {
       useful_ => useful(lty, ctor),
       ref u => (/*bad*/copy *u)
@@ -347,7 +347,7 @@ pub fn is_wild(cx: @MatchCheckCtxt, p: @pat) -> bool {
 }
 
 pub fn missing_ctor(cx: @MatchCheckCtxt,
-                    m: matrix,
+                    m: &matrix,
                     left_ty: ty::t)
                  -> Option<ctor> {
     match ty::get(left_ty).sty {
diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs
index df9b9aa137464..77ad7df531978 100644
--- a/src/librustc/middle/pat_util.rs
+++ b/src/librustc/middle/pat_util.rs
@@ -26,7 +26,7 @@ pub fn pat_id_map(dm: resolve::DefMap, pat: @pat) -> PatIdMap {
     do pat_bindings(dm, pat) |_bm, p_id, _s, n| {
       map.insert(path_to_ident(n), p_id);
     };
-    return map;
+    map
 }
 
 pub fn pat_is_variant_or_struct(dm: resolve::DefMap, pat: @pat) -> bool {
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 58316110b64ed..83ef5a6f3a855 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -130,18 +130,18 @@ pub fn parse_config_(
     let args = args.tail();
     let opts = vec::unzip(opts()).first();
     match getopts::getopts(args, opts) {
-        result::Ok(matches) => {
+        Ok(matches) => {
             if matches.free.len() == 1 {
-                let input_crate = Path(copy *matches.free.head());
+                let input_crate = Path(*matches.free.head());
                 config_from_opts(&input_crate, &matches, program_output)
             } else if matches.free.is_empty() {
-                result::Err(~"no crates specified")
+                Err(~"no crates specified")
             } else {
-                result::Err(~"multiple crates specified")
+                Err(~"multiple crates specified")
             }
         }
-        result::Err(f) => {
-            result::Err(getopts::fail_str(f))
+        Err(f) => {
+            Err(getopts::fail_str(f))
         }
     }
 }

From 743cfce7032e3b0649c22bf1c397280192bf9e95 Mon Sep 17 00:00:00 2001
From: Erick Tryzelaar <erick.tryzelaar@gmail.com>
Date: Tue, 5 Mar 2013 19:39:18 -0800
Subject: [PATCH 9/9] core: convert vec::{last,last_opt} to return references

---
 src/libcore/vec.rs                       | 61 +++++++++++++++---------
 src/librustc/metadata/creader.rs         |  4 +-
 src/librustc/metadata/loader.rs          |  4 +-
 src/librustc/middle/resolve.rs           | 14 +++---
 src/librustc/middle/trans/base.rs        |  2 +-
 src/librustc/middle/trans/debuginfo.rs   | 14 +++---
 src/librustpkg/util.rs                   |  8 ++--
 src/libstd/bigint.rs                     |  4 +-
 src/libstd/json.rs                       |  2 +-
 src/libstd/priority_queue.rs             |  2 +-
 src/libsyntax/ast_util.rs                |  2 +-
 src/libsyntax/attr.rs                    |  2 +-
 src/libsyntax/ext/tt/transcribe.rs       |  2 +-
 src/test/bench/task-perf-alloc-unwind.rs |  2 +-
 src/test/run-pass/zip-same-length.rs     |  2 +-
 15 files changed, 74 insertions(+), 51 deletions(-)

diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 2884d44861072..1be0daf21ba94 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -212,7 +212,7 @@ pub pure fn build_sized_opt<A>(size: Option<uint>,
 
 /// Returns the first element of a vector
 pub pure fn head<T>(v: &r/[T]) -> &r/T {
-    if v.len() == 0 { fail!(~"last_unsafe: empty vector") }
+    if v.len() == 0 { fail!(~"head: empty vector") }
     &v[0]
 }
 
@@ -237,18 +237,15 @@ pub pure fn initn<T>(v: &r/[T], n: uint) -> &r/[T] {
 }
 
 /// Returns the last element of the slice `v`, failing if the slice is empty.
-pub pure fn last<T:Copy>(v: &[const T]) -> T {
-    if len(v) == 0u { fail!(~"last_unsafe: empty vector") }
-    v[len(v) - 1u]
+pub pure fn last<T>(v: &r/[T]) -> &r/T {
+    if v.len() == 0 { fail!(~"last: empty vector") }
+    &v[v.len() - 1]
 }
 
-/**
- * Returns `Some(x)` where `x` is the last element of the slice `v`,
- * or `none` if the vector is empty.
- */
-pub pure fn last_opt<T:Copy>(v: &[const T]) -> Option<T> {
-    if len(v) == 0u { return None; }
-    Some(v[len(v) - 1u])
+/// Returns `Some(x)` where `x` is the last element of the slice `v`, or
+/// `None` if the vector is empty.
+pub pure fn last_opt<T>(v: &r/[T]) -> Option<&r/T> {
+    if v.len() == 0 { None } else { Some(&v[v.len() - 1]) }
 }
 
 /// Return a slice that points into another slice.
@@ -1696,16 +1693,11 @@ impl<T> Container for &[const T] {
 }
 
 pub trait CopyableVector<T> {
-    pure fn last(&self) -> T;
     pure fn slice(&self, start: uint, end: uint) -> ~[T];
 }
 
 /// Extension methods for vectors
 impl<T: Copy> CopyableVector<T> for &[const T] {
-    /// Returns the last element of a `v`, failing if the vector is empty.
-    #[inline]
-    pure fn last(&self) -> T { last(*self) }
-
     /// Returns a copy of the elements from [`start`..`end`) from `v`.
     #[inline]
     pure fn slice(&self, start: uint, end: uint) -> ~[T] {
@@ -1721,6 +1713,8 @@ pub trait ImmutableVector<T> {
     pure fn tailn(&self, n: uint) -> &self/[T];
     pure fn init(&self) -> &self/[T];
     pure fn initn(&self, n: uint) -> &self/[T];
+    pure fn last(&self) -> &self/T;
+    pure fn last_opt(&self) -> Option<&self/T>;
     pure fn foldr<U: Copy>(&self, z: U, p: fn(t: &T, u: U) -> U) -> U;
     pure fn map<U>(&self, f: fn(t: &T) -> U) -> ~[U];
     pure fn mapi<U>(&self, f: fn(uint, t: &T) -> U) -> ~[U];
@@ -1762,6 +1756,14 @@ impl<T> ImmutableVector<T> for &[T] {
     #[inline]
     pure fn initn(&self, n: uint) -> &self/[T] { initn(*self, n) }
 
+    /// Returns the last element of a `v`, failing if the vector is empty.
+    #[inline]
+    pure fn last(&self) -> &self/T { last(*self) }
+
+    /// Returns the last element of a `v`, failing if the vector is empty.
+    #[inline]
+    pure fn last_opt(&self) -> Option<&self/T> { last_opt(*self) }
+
     /// Reduce a vector from right to left
     #[inline]
     pure fn foldr<U:Copy>(&self, z: U, p: fn(t: &T, u: U) -> U) -> U {
@@ -2679,12 +2681,27 @@ mod tests {
 
     #[test]
     fn test_last() {
-        let mut n = last_opt(~[]);
-        assert (n.is_none());
-        n = last_opt(~[1, 2, 3]);
-        assert (n == Some(3));
-        n = last_opt(~[1, 2, 3, 4, 5]);
-        assert (n == Some(5));
+        let mut a = ~[11];
+        assert a.last() == &11;
+        a = ~[11, 12];
+        assert a.last() == &12;
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_last_empty() {
+        let a: ~[int] = ~[];
+        a.last();
+    }
+
+    #[test]
+    fn test_last_opt() {
+        let mut a = ~[];
+        assert a.last_opt() == None;
+        a = ~[11];
+        assert a.last_opt().unwrap() == &11;
+        a = ~[11, 12];
+        assert a.last_opt().unwrap() == &12;
     }
 
     #[test]
diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index 0776611342a3b..ff26000af9749 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -81,7 +81,9 @@ fn warn_if_multiple_versions(e: @mut Env,
 
     if crate_cache.len() != 0u {
         let name = loader::crate_name_from_metas(
-            /*bad*/copy *crate_cache.last().metas);
+            *crate_cache[crate_cache.len() - 1].metas
+        );
+
         let (matches, non_matches) =
             partition(crate_cache.map_to_vec(|&entry| {
                 let othername = loader::crate_name_from_metas(
diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs
index 76080ece3d869..d45cefdbf081f 100644
--- a/src/librustc/metadata/loader.rs
+++ b/src/librustc/metadata/loader.rs
@@ -143,9 +143,9 @@ fn find_library_crate_aux(
 
 pub fn crate_name_from_metas(metas: &[@ast::meta_item]) -> @~str {
     let name_items = attr::find_meta_items_by_name(metas, ~"name");
-    match vec::last_opt(name_items) {
+    match name_items.last_opt() {
         Some(i) => {
-            match attr::get_meta_item_value_str(i) {
+            match attr::get_meta_item_value_str(*i) {
                 Some(n) => n,
                 // FIXME (#2406): Probably want a warning here since the user
                 // is using the wrong type of meta item.
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 004d5ee14ad5b..49898885a6603 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -1438,7 +1438,7 @@ pub impl Resolver {
                                 type_value_ns => AnyNS
                             };
 
-                            let source_ident = full_path.idents.last();
+                            let source_ident = *full_path.idents.last();
                             let subclass = @SingleImport(binding,
                                                          source_ident,
                                                          ns);
@@ -4087,7 +4087,7 @@ pub impl Resolver {
 
                 // First, check to see whether the name is a primitive type.
                 if path.idents.len() == 1 {
-                    let name = path.idents.last();
+                    let name = *path.idents.last();
 
                     match self.primitive_type_table
                             .primitive_types
@@ -4110,7 +4110,7 @@ pub impl Resolver {
                                 debug!("(resolving type) resolved `%s` to \
                                         type %?",
                                        *self.session.str_of(
-                                            path.idents.last()),
+                                            *path.idents.last()),
                                        def);
                                 result_def = Some(def);
                             }
@@ -4296,7 +4296,7 @@ pub impl Resolver {
                                 path.span,
                                 fmt!("not an enum variant: %s",
                                      *self.session.str_of(
-                                         path.idents.last())));
+                                         *path.idents.last())));
                         }
                         None => {
                             self.session.span_err(path.span,
@@ -4418,7 +4418,7 @@ pub impl Resolver {
                                                      namespace);
         }
 
-        return self.resolve_identifier(path.idents.last(),
+        return self.resolve_identifier(*path.idents.last(),
                                        namespace,
                                        check_ribs,
                                        path.span);
@@ -4552,7 +4552,7 @@ pub impl Resolver {
             }
         }
 
-        let name = path.idents.last();
+        let name = *path.idents.last();
         match self.resolve_definition_of_name_in_module(containing_module,
                                                         name,
                                                         namespace,
@@ -4601,7 +4601,7 @@ pub impl Resolver {
             }
         }
 
-        let name = path.idents.last();
+        let name = *path.idents.last();
         match self.resolve_definition_of_name_in_module(containing_module,
                                                         name,
                                                         namespace,
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 76c62919dfa0b..1926b2f2e5df7 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -2207,7 +2207,7 @@ pub fn register_fn_fuller(ccx: @CrateContext,
            ast_map::path_to_str(path, ccx.sess.parse_sess.interner));
 
     let ps = if attr::attrs_contains_name(attrs, "no_mangle") {
-        path_elt_to_str(path.last(), ccx.sess.parse_sess.interner)
+        path_elt_to_str(*path.last(), ccx.sess.parse_sess.interner)
     } else {
         mangle_exported_name(ccx, /*bad*/copy path, node_type)
     };
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index da8e27ba4fffa..61d0594d2274f 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -792,12 +792,14 @@ pub fn create_arg(bcx: block, arg: ast::arg, sp: span)
         match arg.pat.node {
             ast::pat_ident(_, path, _) => {
                 // XXX: This is wrong; it should work for multiple bindings.
-                let mdnode = create_var(tg,
-                                        context.node,
-                                        *cx.sess.str_of(path.idents.last()),
-                                        filemd.node,
-                                        loc.line as int,
-                                        tymd.node);
+                let mdnode = create_var(
+                    tg,
+                    context.node,
+                    *cx.sess.str_of(*path.idents.last()),
+                    filemd.node,
+                    loc.line as int,
+                    tymd.node
+                );
 
                 let mdval = @Metadata {
                     node: mdnode,
diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs
index 57d456f1bbf07..d7428ae15e7ef 100644
--- a/src/librustpkg/util.rs
+++ b/src/librustpkg/util.rs
@@ -57,7 +57,7 @@ pub fn parse_name(id: ~str) -> result::Result<~str, ~str> {
         }
     }
 
-    result::Ok(parts.last())
+    result::Ok(copy *parts.last())
 }
 
 struct ListenerFn {
@@ -516,9 +516,11 @@ pub fn get_pkg(id: ~str,
         return result::Err(~"package not found");
     }
 
-    result::Ok(sort::merge_sort(possibs, |v1, v2| {
+    let possibs = sort::merge_sort(possibs, |v1, v2| {
         v1.vers <= v2.vers
-    }).last())
+    });
+
+    result::Ok(copy *possibs.last())
 }
 
 pub fn add_pkg(pkg: &Package) -> bool {
diff --git a/src/libstd/bigint.rs b/src/libstd/bigint.rs
index 5a0928e6a1182..e8836c5866284 100644
--- a/src/libstd/bigint.rs
+++ b/src/libstd/bigint.rs
@@ -346,7 +346,7 @@ pub impl BigUint {
         }
 
         let mut shift = 0;
-        let mut n = other.data.last();
+        let mut n = *other.data.last();
         while n < (1 << BigDigit::bits - 2) {
             n <<= 1;
             shift += 1;
@@ -384,7 +384,7 @@ pub impl BigUint {
             }
 
             let an = vec::slice(a.data, a.data.len() - n, a.data.len());
-            let bn = b.data.last();
+            let bn = *b.data.last();
             let mut d = ~[];
             let mut carry = 0;
             for vec::rev_each(an) |elt| {
diff --git a/src/libstd/json.rs b/src/libstd/json.rs
index d1a65517aad0f..7993f15f622c8 100644
--- a/src/libstd/json.rs
+++ b/src/libstd/json.rs
@@ -759,7 +759,7 @@ pub fn Decoder(json: Json) -> Decoder {
 priv impl Decoder {
     fn peek(&self) -> &self/Json {
         if self.stack.len() == 0 { self.stack.push(&self.json); }
-        vec::last(self.stack)
+        self.stack[self.stack.len() - 1]
     }
 
     fn pop(&self) -> &self/Json {
diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs
index 4b92bd7543a7d..2a2c655cca9ee 100644
--- a/src/libstd/priority_queue.rs
+++ b/src/libstd/priority_queue.rs
@@ -197,7 +197,7 @@ mod tests {
         let mut sorted = merge_sort(data, le);
         let mut heap = from_vec(data);
         while !heap.is_empty() {
-            assert *heap.top() == sorted.last();
+            assert heap.top() == sorted.last();
             assert heap.pop() == sorted.pop();
         }
     }
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 680101e673c95..ba683004aeec7 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -31,7 +31,7 @@ pub pure fn path_name_i(idents: &[ident], intr: @token::ident_interner)
 }
 
 
-pub pure fn path_to_ident(p: @path) -> ident { vec::last(p.idents) }
+pub pure fn path_to_ident(p: @path) -> ident { copy *p.idents.last() }
 
 pub pure fn local_def(id: node_id) -> def_id {
     ast::def_id { crate: local_crate, node: id }
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 7739a862432ee..fb7143f7c1438 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -229,7 +229,7 @@ fn last_meta_item_by_name(items: &[@ast::meta_item], name: &str)
     -> Option<@ast::meta_item> {
 
     let items = attr::find_meta_items_by_name(items, name);
-    vec::last_opt(items)
+    items.last_opt().map(|item| **item)
 }
 
 pub fn last_meta_item_value_str_by_name(items: &[@ast::meta_item], name: &str)
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index 79264f7adf034..116ecc37d2e18 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -167,7 +167,7 @@ pub fn tt_next_token(r: @mut TtReader) -> TokenAndSpan {
     while r.cur.idx >= r.cur.readme.len() {
         /* done with this set; pop or repeat? */
         if ! r.cur.dotdotdoted
-            || r.repeat_idx.last() == r.repeat_len.last() - 1 {
+            || { *r.repeat_idx.last() == *r.repeat_len.last() - 1 } {
 
             match r.cur.up {
               None => {
diff --git a/src/test/bench/task-perf-alloc-unwind.rs b/src/test/bench/task-perf-alloc-unwind.rs
index 05781b20a9b3f..4a372d016f9cf 100644
--- a/src/test/bench/task-perf-alloc-unwind.rs
+++ b/src/test/bench/task-perf-alloc-unwind.rs
@@ -93,7 +93,7 @@ fn recurse_or_fail(depth: int, st: Option<State>) {
                 fn_box: || @Cons((), fn_box()),
                 tuple: (@Cons((), st.tuple.first()),
                         ~Cons((), @*st.tuple.second())),
-                vec: st.vec + ~[@Cons((), st.vec.last())],
+                vec: st.vec + ~[@Cons((), *st.vec.last())],
                 res: r(@Cons((), st.res._l))
             }
           }
diff --git a/src/test/run-pass/zip-same-length.rs b/src/test/run-pass/zip-same-length.rs
index 29b58cd643115..fdb6989b7bb37 100644
--- a/src/test/run-pass/zip-same-length.rs
+++ b/src/test/run-pass/zip-same-length.rs
@@ -35,5 +35,5 @@ pub fn main() {
     let ps = vec::zip(chars, ints);
 
     assert (ps.head() == &('a', 1u));
-    assert (ps.last() == (j as char, 10u));
+    assert (ps.last() == &(j as char, 10u));
 }