about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-05-10 20:35:00 -0700
committerbors <bors@rust-lang.org>2013-05-10 20:35:00 -0700
commit9f106a643e6cdf2f3c8d62bcec61da087ed24c5b (patch)
treeb5593b086685c556b08f9772daff3e1391b1356f
parentc49cf8b3300a97201058debd63b0f7aef34d3c35 (diff)
parent60803e5fc81ed7065c91c0b1725dbbd4da0af3f7 (diff)
downloadrust-9f106a643e6cdf2f3c8d62bcec61da087ed24c5b.tar.gz
rust-9f106a643e6cdf2f3c8d62bcec61da087ed24c5b.zip
auto merge of #6260 : alexcrichton/rust/issue-3466-no-swap, r=pcwalton
There may be a more efficient implementation of `core::util::swap_ptr`. The issue mentioned using `move_val_init`, but I couldn't figure out what that did, so I just used `copy_memory` a few times instead.

I'm not exactly the best at reading LLVM generated by rust, but this does appear to be optimized away just as expected (when possible).
-rw-r--r--doc/rust.md31
-rw-r--r--doc/tutorial-ffi.md4
-rw-r--r--src/libcore/cell.rs5
-rw-r--r--src/libcore/comm.rs29
-rw-r--r--src/libcore/hashmap.rs24
-rw-r--r--src/libcore/pipes.rs29
-rw-r--r--src/libcore/util.rs74
-rw-r--r--src/libcore/vec.rs81
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs4
-rw-r--r--src/librustc/middle/dataflow.rs5
-rw-r--r--src/librustc/middle/liveness.rs19
-rw-r--r--src/librustc/middle/mem_categorization.rs2
-rw-r--r--src/librustc/middle/moves.rs5
-rw-r--r--src/librustc/middle/trans/expr.rs27
-rw-r--r--src/librustc/middle/trans/type_use.rs2
-rw-r--r--src/librustc/middle/ty.rs1
-rw-r--r--src/librustc/middle/typeck/check/mod.rs14
-rw-r--r--src/librustc/middle/typeck/check/regionck.rs1
-rw-r--r--src/librusti/rusti.rc4
-rw-r--r--src/libstd/deque.rs6
-rw-r--r--src/libstd/future.rs7
-rw-r--r--src/libstd/priority_queue.rs24
-rw-r--r--src/libstd/rc.rs20
-rw-r--r--src/libstd/sort.rs59
-rw-r--r--src/libstd/sort_stage0.rs59
-rw-r--r--src/libstd/treemap.rs20
-rw-r--r--src/libstd/workcache.rs9
-rw-r--r--src/libsyntax/ast.rs1
-rw-r--r--src/libsyntax/fold.rs3
-rw-r--r--src/libsyntax/parse/obsolete.rs5
-rw-r--r--src/libsyntax/parse/parser.rs10
-rw-r--r--src/libsyntax/print/pprust.rs6
-rw-r--r--src/libsyntax/visit.rs4
-rw-r--r--src/test/bench/core-std.rs3
-rw-r--r--src/test/bench/msgsend-ring-pipes.rs7
-rw-r--r--src/test/bench/shootout-k-nucleotide-pipes.rs4
-rw-r--r--src/test/compile-fail/liveness-assign-imm-local-in-swap.rs28
-rw-r--r--src/test/compile-fail/liveness-swap-uninit.rs16
-rw-r--r--src/test/compile-fail/moves-based-on-type-exprs.rs2
-rw-r--r--src/test/compile-fail/swap-no-lval.rs15
-rw-r--r--src/test/run-pass/borrowck-mut-uniq.rs6
-rw-r--r--src/test/run-pass/issue-2718.rs21
-rw-r--r--src/test/run-pass/regions-infer-borrow-scope-addr-of.rs4
-rw-r--r--src/test/run-pass/swap-1.rs5
-rw-r--r--src/test/run-pass/swap-2.rs6
-rw-r--r--src/test/run-pass/swap-overlapping.rs7
-rw-r--r--src/test/run-pass/unique-swap.rs4
-rw-r--r--src/test/run-pass/weird-exprs.rs4
48 files changed, 296 insertions, 430 deletions
diff --git a/doc/rust.md b/doc/rust.md
index ac7125be424..60848441e4e 100644
--- a/doc/rust.md
+++ b/doc/rust.md
@@ -1946,35 +1946,6 @@ fn avg(v: &[float]) -> float {
 }
 ~~~~
 
-#### Swap expressions
-
-A _swap expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) followed by a bi-directional arrow (`<->`) and another [lvalue](#lvalues-rvalues-and-temporaries).
-
-Evaluating a swap expression causes, as a side effect, the values held in the left-hand-side and right-hand-side [lvalues](#lvalues-rvalues-and-temporaries) to be exchanged indivisibly.
-
-Evaluating a swap expression neither changes reference counts,
-nor deeply copies any owned structure pointed to by the moved [rvalue](#lvalues-rvalues-and-temporaries).
-Instead, the swap expression represents an indivisible *exchange of ownership*,
-between the right-hand-side and the left-hand-side of the expression.
-No allocation or destruction is entailed.
-
-An example of three different swap expressions:
-
-~~~~~~~~
-# let mut x = &mut [0];
-# let mut a = &mut [0];
-# let i = 0;
-# struct S1 { z: int };
-# struct S2 { c: int };
-# let mut y = S1{z: 0};
-# let mut b = S2{c: 0};
-
-x <-> a;
-x[i] <-> a[i];
-y.z <-> b.c;
-~~~~~~~~
-
-
 #### Assignment expressions
 
 An _assignment expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) expression followed by an
@@ -2015,7 +1986,7 @@ as
 == !=
 &&
 ||
-= <->
+=
 ~~~~
 
 Operators at the same precedence level are evaluated left-to-right.
diff --git a/doc/tutorial-ffi.md b/doc/tutorial-ffi.md
index 2a3d8dc1481..d8367fbdc2d 100644
--- a/doc/tutorial-ffi.md
+++ b/doc/tutorial-ffi.md
@@ -151,6 +151,7 @@ wrapping `malloc` and `free`:
 ~~~~
 use core::libc::{c_void, size_t, malloc, free};
 use core::unstable::intrinsics;
+use core::util;
 
 // a wrapper around the handle returned by the foreign code
 pub struct Unique<T> {
@@ -184,7 +185,8 @@ impl<T: Owned> Drop for Unique<T> {
     fn finalize(&self) {
         unsafe {
             let mut x = intrinsics::init(); // dummy value to swap in
-            x <-> *self.ptr; // moving the object out is needed to call the destructor
+            // moving the object out is needed to call the destructor
+            util::replace_ptr(self.ptr, x);
             free(self.ptr as *c_void)
         }
     }
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index c7f9e377571..18e75fb1aa9 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -12,6 +12,7 @@
 
 use cast::transmute_mut;
 use prelude::*;
+use util::replace;
 
 /*
 A dynamic, mutable location.
@@ -48,9 +49,7 @@ pub impl<T> Cell<T> {
             fail!(~"attempt to take an empty cell");
         }
 
-        let mut value = None;
-        value <-> self.value;
-        value.unwrap()
+        replace(&mut self.value, None).unwrap()
     }
 
     /// Returns the value, failing if the cell is full.
diff --git a/src/libcore/comm.rs b/src/libcore/comm.rs
index 7eaa8535493..140eb41fdf3 100644
--- a/src/libcore/comm.rs
+++ b/src/libcore/comm.rs
@@ -21,6 +21,7 @@ use uint;
 use unstable;
 use vec;
 use unstable::Exclusive;
+use util::replace;
 
 use pipes::{recv, try_recv, wait_many, peek, PacketHeader};
 
@@ -149,9 +150,8 @@ impl<T: Owned> GenericChan<T> for Chan<T> {
     #[inline(always)]
     fn send(&self, x: T) {
         unsafe {
-            let mut endp = None;
             let mut self_endp = transmute_mut(&self.endp);
-            endp <-> *self_endp;
+            let endp = replace(self_endp, None);
             *self_endp = Some(streamp::client::data(endp.unwrap(), x))
         }
     }
@@ -161,9 +161,8 @@ impl<T: Owned> GenericSmartChan<T> for Chan<T> {
     #[inline(always)]
     fn try_send(&self, x: T) -> bool {
         unsafe {
-            let mut endp = None;
             let mut self_endp = transmute_mut(&self.endp);
-            endp <-> *self_endp;
+            let endp = replace(self_endp, None);
             match streamp::client::try_data(endp.unwrap(), x) {
                 Some(next) => {
                     *self_endp = Some(next);
@@ -179,9 +178,8 @@ impl<T: Owned> GenericPort<T> for Port<T> {
     #[inline(always)]
     fn recv(&self) -> T {
         unsafe {
-            let mut endp = None;
             let mut self_endp = transmute_mut(&self.endp);
-            endp <-> *self_endp;
+            let endp = replace(self_endp, None);
             let streamp::data(x, endp) = recv(endp.unwrap());
             *self_endp = Some(endp);
             x
@@ -191,9 +189,8 @@ impl<T: Owned> GenericPort<T> for Port<T> {
     #[inline(always)]
     fn try_recv(&self) -> Option<T> {
         unsafe {
-            let mut endp = None;
             let mut self_endp = transmute_mut(&self.endp);
-            endp <-> *self_endp;
+            let endp = replace(self_endp, None);
             match try_recv(endp.unwrap()) {
                 Some(streamp::data(x, endp)) => {
                     *self_endp = Some(endp);
@@ -209,14 +206,13 @@ impl<T: Owned> Peekable<T> for Port<T> {
     #[inline(always)]
     fn peek(&self) -> bool {
         unsafe {
-            let mut endp = None;
             let mut self_endp = transmute_mut(&self.endp);
-            endp <-> *self_endp;
+            let mut endp = replace(self_endp, None);
             let peek = match endp {
                 Some(ref mut endp) => peek(endp),
                 None => fail!(~"peeking empty stream")
             };
-            *self_endp <-> endp;
+            *self_endp = endp;
             peek
         }
     }
@@ -267,8 +263,7 @@ impl<T:Owned> GenericPort<T> for PortSet<T> {
             let mut result = None;
             // we have to swap the ports array so we aren't borrowing
             // aliasable mutable memory.
-            let mut ports = ~[];
-            ports <-> *self_ports;
+            let mut ports = replace(self_ports, ~[]);
             while result.is_none() && ports.len() > 0 {
                 let i = wait_many(ports);
                 match ports[i].try_recv() {
@@ -281,7 +276,7 @@ impl<T:Owned> GenericPort<T> for PortSet<T> {
                     }
                 }
             }
-            ports <-> *self_ports;
+            *self_ports = ports;
             result
         }
     }
@@ -320,8 +315,7 @@ impl<T: Owned> GenericChan<T> for SharedChan<T> {
     fn send(&self, x: T) {
         let mut xx = Some(x);
         do self.ch.with_imm |chan| {
-            let mut x = None;
-            x <-> xx;
+            let x = replace(&mut xx, None);
             chan.send(x.unwrap())
         }
     }
@@ -331,8 +325,7 @@ impl<T: Owned> GenericSmartChan<T> for SharedChan<T> {
     fn try_send(&self, x: T) -> bool {
         let mut xx = Some(x);
         do self.ch.with_imm |chan| {
-            let mut x = None;
-            x <-> xx;
+            let x = replace(&mut xx, None);
             chan.try_send(x.unwrap())
         }
     }
diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs
index b5ae07208fc..590d4ab3bcb 100644
--- a/src/libcore/hashmap.rs
+++ b/src/libcore/hashmap.rs
@@ -176,16 +176,13 @@ priv impl<K:Hash + Eq,V> HashMap<K, V> {
     /// Expands the capacity of the array and re-insert each of the
     /// existing buckets.
     fn resize(&mut self, new_capacity: uint) {
-        let old_capacity = self.buckets.len();
         self.resize_at = resize_at(new_capacity);
 
-        let mut old_buckets = vec::from_fn(new_capacity, |_| None);
-        self.buckets <-> old_buckets;
+        let old_buckets = replace(&mut self.buckets,
+                                  vec::from_fn(new_capacity, |_| None));
 
         self.size = 0;
-        for uint::range(0, old_capacity) |i| {
-            let mut bucket = None;
-            bucket <-> old_buckets[i];
+        do vec::consume(old_buckets) |_, bucket| {
             self.insert_opt_bucket(bucket);
         }
     }
@@ -265,13 +262,11 @@ priv impl<K:Hash + Eq,V> HashMap<K, V> {
         };
 
         let len_buckets = self.buckets.len();
-        let mut bucket = None;
-        self.buckets[idx] <-> bucket;
+        let bucket = replace(&mut self.buckets[idx], None);
 
         let value = match bucket {
             None => None,
-            Some(bucket) => {
-                let Bucket{value: value, _} = bucket;
+            Some(Bucket{value, _}) => {
                 Some(value)
             },
         };
@@ -281,8 +276,7 @@ priv impl<K:Hash + Eq,V> HashMap<K, V> {
         let size = self.size - 1;
         idx = self.next_bucket(idx, len_buckets);
         while self.buckets[idx].is_some() {
-            let mut bucket = None;
-            bucket <-> self.buckets[idx];
+            let bucket = replace(&mut self.buckets[idx], None);
             self.insert_opt_bucket(bucket);
             idx = self.next_bucket(idx, len_buckets);
         }
@@ -613,15 +607,13 @@ pub impl<K: Hash + Eq, V> HashMap<K, V> {
     }
 
     fn consume(&mut self, f: &fn(K, V)) {
-        let mut buckets = ~[];
-        self.buckets <-> buckets;
+        let buckets = replace(&mut self.buckets, ~[]);
         self.size = 0;
 
         do vec::consume(buckets) |_, bucket| {
             match bucket {
                 None => {},
-                Some(bucket) => {
-                    let Bucket{key: key, value: value, _} = bucket;
+                Some(Bucket{key, value, _}) => {
                     f(key, value)
                 }
             }
diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs
index 8301254fbdd..fe9c78198bb 100644
--- a/src/libcore/pipes.rs
+++ b/src/libcore/pipes.rs
@@ -93,6 +93,7 @@ use unstable::intrinsics;
 use ptr;
 use task;
 use vec;
+use util::replace;
 
 static SPIN_COUNT: uint = 0;
 
@@ -428,8 +429,7 @@ fn try_recv_<T:Owned>(p: &mut Packet<T>) -> Option<T> {
     // optimistic path
     match p.header.state {
       Full => {
-        let mut payload = None;
-        payload <-> p.payload;
+        let payload = replace(&mut p.payload, None);
         p.header.state = Empty;
         return Some(payload.unwrap())
       },
@@ -480,8 +480,7 @@ fn try_recv_<T:Owned>(p: &mut Packet<T>) -> Option<T> {
             fail!(~"blocking on already blocked packet")
           },
           Full => {
-            let mut payload = None;
-            payload <-> p.payload;
+            let payload = replace(&mut p.payload, None);
             let old_task = swap_task(&mut p.header.blocked_task, ptr::null());
             if !old_task.is_null() {
                 unsafe {
@@ -675,8 +674,7 @@ impl<T:Owned,Tbuffer:Owned> Drop for SendPacketBuffered<T,Tbuffer> {
         unsafe {
             let this: &mut SendPacketBuffered<T,Tbuffer> = transmute(self);
             if this.p != None {
-                let mut p = None;
-                p <-> this.p;
+                let p = replace(&mut this.p, None);
                 sender_terminate(p.unwrap())
             }
         }
@@ -695,9 +693,7 @@ pub fn SendPacketBuffered<T,Tbuffer>(p: *mut Packet<T>)
 
 pub impl<T,Tbuffer> SendPacketBuffered<T,Tbuffer> {
     fn unwrap(&mut self) -> *mut Packet<T> {
-        let mut p = None;
-        p <-> self.p;
-        p.unwrap()
+        replace(&mut self.p, None).unwrap()
     }
 
     fn header(&mut self) -> *mut PacketHeader {
@@ -713,9 +709,7 @@ pub impl<T,Tbuffer> SendPacketBuffered<T,Tbuffer> {
 
     fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> {
         //error!("send reuse_buffer");
-        let mut tmp = None;
-        tmp <-> self.buffer;
-        tmp.unwrap()
+        replace(&mut self.buffer, None).unwrap()
     }
 }
 
@@ -738,8 +732,7 @@ impl<T:Owned,Tbuffer:Owned> Drop for RecvPacketBuffered<T,Tbuffer> {
         unsafe {
             let this: &mut RecvPacketBuffered<T,Tbuffer> = transmute(self);
             if this.p != None {
-                let mut p = None;
-                p <-> this.p;
+                let p = replace(&mut this.p, None);
                 receiver_terminate(p.unwrap())
             }
         }
@@ -748,15 +741,11 @@ impl<T:Owned,Tbuffer:Owned> Drop for RecvPacketBuffered<T,Tbuffer> {
 
 pub impl<T:Owned,Tbuffer:Owned> RecvPacketBuffered<T, Tbuffer> {
     fn unwrap(&mut self) -> *mut Packet<T> {
-        let mut p = None;
-        p <-> self.p;
-        p.unwrap()
+        replace(&mut self.p, None).unwrap()
     }
 
     fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> {
-        let mut tmp = None;
-        tmp <-> self.buffer;
-        tmp.unwrap()
+        replace(&mut self.buffer, None).unwrap()
     }
 }
 
diff --git a/src/libcore/util.rs b/src/libcore/util.rs
index 43616ebfd30..db9a17cf97f 100644
--- a/src/libcore/util.rs
+++ b/src/libcore/util.rs
@@ -15,6 +15,7 @@ Miscellaneous helpers for common patterns.
 */
 
 use prelude::*;
+use unstable::intrinsics;
 
 /// The identity function.
 #[inline(always)]
@@ -34,12 +35,12 @@ pub fn ignore<T>(_x: T) { }
 #[inline(always)]
 pub fn with<T,R>(
     ptr: @mut T,
-    mut value: T,
+    value: T,
     op: &fn() -> R) -> R
 {
-    value <-> *ptr;
+    let prev = replace(ptr, value);
     let result = op();
-    *ptr = value;
+    *ptr = prev;
     return result;
 }
 
@@ -49,7 +50,65 @@ pub fn with<T,R>(
  */
 #[inline(always)]
 pub fn swap<T>(x: &mut T, y: &mut T) {
-    *x <-> *y;
+    unsafe {
+        swap_ptr(ptr::to_mut_unsafe_ptr(x), ptr::to_mut_unsafe_ptr(y));
+    }
+}
+
+/**
+ * Swap the values at two mutable locations of the same type, without
+ * deinitialising or copying either one.
+ */
+#[inline]
+#[cfg(not(stage0))]
+pub unsafe fn swap_ptr<T>(x: *mut T, y: *mut T) {
+    if x == y { return }
+
+    // Give ourselves some scratch space to work with
+    let mut tmp: T = intrinsics::uninit();
+    let t = ptr::to_mut_unsafe_ptr(&mut tmp);
+
+    // Perform the swap
+    ptr::copy_memory(t, x, 1);
+    ptr::copy_memory(x, y, 1);
+    ptr::copy_memory(y, t, 1);
+
+    // y and t now point to the same thing, but we need to completely forget t
+    // because it's no longer relevant.
+    cast::forget(tmp);
+}
+
+/**
+ * Swap the values at two mutable locations of the same type, without
+ * deinitialising or copying either one.
+ */
+#[inline]
+#[cfg(stage0)]
+pub unsafe fn swap_ptr<T>(x: *mut T, y: *mut T) {
+    if x == y { return }
+
+    // Give ourselves some scratch space to work with
+    let mut tmp: T = intrinsics::init();
+    let t = ptr::to_mut_unsafe_ptr(&mut tmp);
+
+    // Perform the swap
+    ptr::copy_memory(t, x, 1);
+    ptr::copy_memory(x, y, 1);
+    ptr::copy_memory(y, t, 1);
+
+    // y and t now point to the same thing, but we need to completely forget t
+    // because it's no longer relevant.
+    cast::forget(tmp);
+}
+
+/**
+ * Replace the value at a mutable location with a new one, returning the old
+ * value, without deinitialising or copying either one.
+ */
+#[inline(always)]
+pub fn replace<T>(dest: &mut T, mut src: T) -> T {
+    swap(dest, &mut src);
+    src
 }
 
 /**
@@ -57,10 +116,9 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
  * value, without deinitialising or copying either one.
  */
 #[inline(always)]
-pub fn replace<T>(dest: &mut T, src: T) -> T {
-    let mut tmp = src;
-    swap(dest, &mut tmp);
-    tmp
+pub unsafe fn replace_ptr<T>(dest: *mut T, mut src: T) -> T {
+    swap_ptr(dest, ptr::to_mut_unsafe_ptr(&mut src));
+    src
 }
 
 /// A non-copyable dummy type.
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 7eba2cbf0cc..77314b173d9 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -29,6 +29,7 @@ use sys;
 use uint;
 use unstable::intrinsics;
 use vec;
+use util;
 
 #[cfg(not(test))] use cmp::Equiv;
 
@@ -470,7 +471,7 @@ pub fn shift<T>(v: &mut ~[T]) -> T {
         let next_ln = v.len() - 1;
 
         // Save the last element. We're going to overwrite its position
-        let mut work_elt = v.pop();
+        let work_elt = v.pop();
         // We still should have room to work where what last element was
         assert!(capacity(v) >= ln);
         // Pretend like we have the original length so we can use
@@ -501,16 +502,14 @@ pub fn shift<T>(v: &mut ~[T]) -> T {
         // Swap out the element we want from the end
         let vp = raw::to_mut_ptr(*v);
         let vp = ptr::mut_offset(vp, next_ln - 1);
-        *vp <-> work_elt;
 
-        work_elt
+        util::replace_ptr(vp, work_elt)
     }
 }
 
 /// Prepend an element to the vector
 pub fn unshift<T>(v: &mut ~[T], x: T) {
-    let mut vv = ~[x];
-    *v <-> vv;
+    let vv = util::replace(v, ~[x]);
     v.push_all_move(vv);
 }
 
@@ -523,7 +522,7 @@ pub fn insert<T>(v: &mut ~[T], i: uint, x: T) {
     v.push(x);
     let mut j = len;
     while j > i {
-        v[j] <-> v[j - 1];
+        swap(*v, j, j - 1);
         j -= 1;
     }
 }
@@ -536,7 +535,7 @@ pub fn remove<T>(v: &mut ~[T], i: uint) -> T {
 
     let mut j = i;
     while j < len - 1 {
-        v[j] <-> v[j + 1];
+        swap(*v, j, j + 1);
         j += 1;
     }
     v.pop()
@@ -550,10 +549,9 @@ pub fn consume<T>(mut v: ~[T], f: &fn(uint, v: T)) {
                 // holes we create in the vector. That ensures that, if the
                 // iterator fails then we won't try to clean up the consumed
                 // elements during unwinding
-                let mut x = intrinsics::init();
+                let x = intrinsics::init();
                 let p = ptr::mut_offset(p, i);
-                x <-> *p;
-                f(i, x);
+                f(i, util::replace_ptr(p, x));
             }
         }
 
@@ -572,10 +570,9 @@ pub fn consume_reverse<T>(mut v: ~[T], f: &fn(uint, v: T)) {
                 // holes we create in the vector. That ensures that, if the
                 // iterator fails then we won't try to clean up the consumed
                 // elements during unwinding
-                let mut x = intrinsics::init();
+                let x = intrinsics::init();
                 let p = ptr::mut_offset(p, i);
-                x <-> *p;
-                f(i, x);
+                f(i, util::replace_ptr(p, x));
             }
         }
 
@@ -592,8 +589,7 @@ pub fn pop<T>(v: &mut ~[T]) -> T {
     }
     let valptr = ptr::to_mut_unsafe_ptr(&mut v[ln - 1u]);
     unsafe {
-        let mut val = intrinsics::uninit();
-        val <-> *valptr;
+        let val = util::replace_ptr(valptr, intrinsics::uninit());
         raw::set_len(v, ln - 1u);
         val
     }
@@ -607,8 +603,7 @@ pub fn pop<T>(v: &mut ~[T]) -> T {
     }
     let valptr = ptr::to_mut_unsafe_ptr(&mut v[ln - 1u]);
     unsafe {
-        let mut val = intrinsics::init();
-        val <-> *valptr;
+        let val = util::replace_ptr(valptr, intrinsics::init());
         raw::set_len(v, ln - 1u);
         val
     }
@@ -626,7 +621,7 @@ pub fn swap_remove<T>(v: &mut ~[T], index: uint) -> T {
         fail!(fmt!("vec::swap_remove - index %u >= length %u", index, ln));
     }
     if index < ln - 1 {
-        v[index] <-> v[ln - 1];
+        swap(*v, index, ln - 1);
     }
     v.pop()
 }
@@ -682,8 +677,8 @@ pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) {
     unsafe {
         do as_mut_buf(rhs) |p, len| {
             for uint::range(0, len) |i| {
-                let mut x = intrinsics::uninit();
-                x <-> *ptr::mut_offset(p, i);
+                let x = util::replace_ptr(ptr::mut_offset(p, i),
+                                          intrinsics::uninit());
                 push(&mut *v, x);
             }
         }
@@ -699,8 +694,8 @@ pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) {
     unsafe {
         do as_mut_buf(rhs) |p, len| {
             for uint::range(0, len) |i| {
-                let mut x = intrinsics::init();
-                x <-> *ptr::mut_offset(p, i);
+                let x = util::replace_ptr(ptr::mut_offset(p, i),
+                                          intrinsics::init());
                 push(&mut *v, x);
             }
         }
@@ -716,8 +711,7 @@ pub fn truncate<T>(v: &mut ~[T], newlen: uint) {
         unsafe {
             // This loop is optimized out for non-drop types.
             for uint::range(newlen, oldlen) |i| {
-                let mut dropped = intrinsics::uninit();
-                dropped <-> *ptr::mut_offset(p, i);
+                util::replace_ptr(ptr::mut_offset(p, i), intrinsics::uninit());
             }
         }
     }
@@ -732,8 +726,7 @@ pub fn truncate<T>(v: &mut ~[T], newlen: uint) {
         unsafe {
             // This loop is optimized out for non-drop types.
             for uint::range(newlen, oldlen) |i| {
-                let mut dropped = intrinsics::init();
-                dropped <-> *ptr::mut_offset(p, i);
+                util::replace_ptr(ptr::mut_offset(p, i), intrinsics::init());
             }
         }
     }
@@ -758,14 +751,14 @@ pub fn dedup<T:Eq>(v: &mut ~[T]) {
                 // last_written < next_to_read < ln
                 if *ptr::mut_offset(p, next_to_read) ==
                     *ptr::mut_offset(p, last_written) {
-                    let mut dropped = intrinsics::uninit();
-                    dropped <-> *ptr::mut_offset(p, next_to_read);
+                    util::replace_ptr(ptr::mut_offset(p, next_to_read),
+                                      intrinsics::uninit());
                 } else {
                     last_written += 1;
                     // last_written <= next_to_read < ln
                     if next_to_read != last_written {
-                        *ptr::mut_offset(p, last_written) <->
-                            *ptr::mut_offset(p, next_to_read);
+                        util::swap_ptr(ptr::mut_offset(p, last_written),
+                                       ptr::mut_offset(p, next_to_read));
                     }
                 }
                 // last_written <= next_to_read < ln
@@ -796,14 +789,14 @@ pub fn dedup<T:Eq>(v: &mut ~[T]) {
                 // last_written < next_to_read < ln
                 if *ptr::mut_offset(p, next_to_read) ==
                     *ptr::mut_offset(p, last_written) {
-                    let mut dropped = intrinsics::init();
-                    dropped <-> *ptr::mut_offset(p, next_to_read);
+                    util::replace_ptr(ptr::mut_offset(p, next_to_read),
+                                      intrinsics::init());
                 } else {
                     last_written += 1;
                     // last_written <= next_to_read < ln
                     if next_to_read != last_written {
-                        *ptr::mut_offset(p, last_written) <->
-                            *ptr::mut_offset(p, next_to_read);
+                        util::swap_ptr(ptr::mut_offset(p, last_written),
+                                       ptr::mut_offset(p, next_to_read));
                     }
                 }
                 // last_written <= next_to_read < ln
@@ -1028,7 +1021,7 @@ pub fn retain<T>(v: &mut ~[T], f: &fn(t: &T) -> bool) {
         if !f(&v[i]) {
             deleted += 1;
         } else if deleted > 0 {
-            v[i - deleted] <-> v[i];
+            swap(*v, i - deleted, i);
         }
     }
 
@@ -1429,15 +1422,25 @@ pub fn zip<T, U>(mut v: ~[T], mut u: ~[U]) -> ~[(T, U)] {
  * * a - The index of the first element
  * * b - The index of the second element
  */
+#[inline(always)]
 pub fn swap<T>(v: &mut [T], a: uint, b: uint) {
-    v[a] <-> v[b];
+    unsafe {
+        // Can't take two mutable loans from one vector, so instead just cast
+        // them to their raw pointers to do the swap
+        let pa: *mut T = ptr::to_mut_unsafe_ptr(&mut v[a]);
+        let pb: *mut T = ptr::to_mut_unsafe_ptr(&mut v[b]);
+        util::swap_ptr(pa, pb);
+    }
 }
 
 /// Reverse the order of elements in a vector, in place
 pub fn reverse<T>(v: &mut [T]) {
     let mut i: uint = 0;
     let ln = len::<T>(v);
-    while i < ln / 2 { v[i] <-> v[ln - i - 1]; i += 1; }
+    while i < ln / 2 {
+        swap(v, i, ln - i - 1);
+        i += 1;
+    }
 }
 
 /// Returns a vector with the order of elements reversed
@@ -2476,6 +2479,7 @@ pub mod raw {
     use sys;
     use unstable::intrinsics;
     use vec::{UnboxedVecRepr, as_const_buf, as_mut_buf, len, with_capacity};
+    use util;
 
     /// The internal representation of a (boxed) vector
     pub struct VecRepr {
@@ -2573,8 +2577,7 @@ pub mod raw {
     pub unsafe fn init_elem<T>(v: &mut [T], i: uint, val: T) {
         let mut box = Some(val);
         do as_mut_buf(v) |p, _len| {
-            let mut box2 = None;
-            box2 <-> box;
+            let box2 = util::replace(&mut box, None);
             intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i)),
                                       box2.unwrap());
         }
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index 27f6ae33ba3..2f116cb1b28 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -758,10 +758,6 @@ fn check_loans_in_expr<'a>(expr: @ast::expr,
     }
 
     match expr.node {
-      ast::expr_swap(l, r) => {
-        self.check_assignment(l);
-        self.check_assignment(r);
-      }
       ast::expr_assign(dest, _) |
       ast::expr_assign_op(_, dest, _) => {
         self.check_assignment(dest);
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index f1fa5144f4c..dc08fb39ad9 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -698,11 +698,6 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> {
                 self.walk_expr(l, in_out, loop_scopes);
             }
 
-            ast::expr_swap(l, r) => {
-                self.walk_expr(l, in_out, loop_scopes);
-                self.walk_expr(r, in_out, loop_scopes);
-            }
-
             ast::expr_vec(ref exprs, _) => {
                 self.walk_exprs(*exprs, in_out, loop_scopes)
             }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 0bd73a15d50..52274f3d305 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -523,7 +523,7 @@ fn visit_expr(expr: @expr, self: @mut IrMaps, vt: vt<@mut IrMaps>) {
       expr_binary(*) | expr_addr_of(*) | expr_copy(*) | expr_loop_body(*) |
       expr_do_body(*) | expr_cast(*) | expr_unary(*) | expr_break(_) |
       expr_again(_) | expr_lit(_) | expr_ret(*) | expr_block(*) |
-      expr_assign(*) | expr_swap(*) | expr_assign_op(*) | expr_mac(*) |
+      expr_assign(*) | expr_assign_op(*) | expr_mac(*) |
       expr_struct(*) | expr_repeat(*) | expr_paren(*) |
       expr_inline_asm(*) => {
           visit::visit_expr(expr, self, vt);
@@ -1141,21 +1141,6 @@ pub impl Liveness {
             self.propagate_through_expr(r, succ)
           }
 
-          expr_swap(l, r) => {
-            // see comment on lvalues in
-            // propagate_through_lvalue_components()
-
-            // I count swaps as `used` cause it might be something like:
-            //    foo.bar <-> x
-            // and I am too lazy to distinguish this case from
-            //    y <-> x
-            // (where both x, y are unused) just for a warning.
-            let succ = self.write_lvalue(r, succ, ACC_WRITE|ACC_READ|ACC_USE);
-            let succ = self.write_lvalue(l, succ, ACC_WRITE|ACC_READ|ACC_USE);
-            let succ = self.propagate_through_lvalue_components(r, succ);
-            self.propagate_through_lvalue_components(l, succ)
-          }
-
           expr_assign_op(_, l, r) => {
             // see comment on lvalues in
             // propagate_through_lvalue_components()
@@ -1533,7 +1518,7 @@ fn check_expr(expr: @expr, self: @Liveness, vt: vt<@Liveness>) {
       expr_vstore(*) | expr_vec(*) | expr_tup(*) | expr_log(*) |
       expr_binary(*) | expr_copy(*) | expr_loop_body(*) | expr_do_body(*) |
       expr_cast(*) | expr_unary(*) | expr_ret(*) | expr_break(*) |
-      expr_again(*) | expr_lit(_) | expr_block(*) | expr_swap(*) |
+      expr_again(*) | expr_lit(_) | expr_block(*) |
       expr_mac(*) | expr_addr_of(*) | expr_struct(*) | expr_repeat(*) |
       expr_paren(*) => {
         visit::visit_expr(expr, self, vt);
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 0e819c66f09..7675efa76f4 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -413,7 +413,7 @@ pub impl mem_categorization_ctxt {
 
           ast::expr_paren(e) => self.cat_expr_unadjusted(e),
 
-          ast::expr_addr_of(*) | ast::expr_call(*) | ast::expr_swap(*) |
+          ast::expr_addr_of(*) | ast::expr_call(*) |
           ast::expr_assign(*) | ast::expr_assign_op(*) |
           ast::expr_fn_block(*) | ast::expr_ret(*) | ast::expr_loop_body(*) |
           ast::expr_do_body(*) | ast::expr_unary(*) |
diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs
index 040ff30f9e6..2471e383bca 100644
--- a/src/librustc/middle/moves.rs
+++ b/src/librustc/middle/moves.rs
@@ -650,11 +650,6 @@ pub impl VisitContext {
                 self.consume_expr(count, visitor);
             }
 
-            expr_swap(lhs, rhs) => {
-                self.use_expr(lhs, Read, visitor);
-                self.use_expr(rhs, Read, visitor);
-            }
-
             expr_loop_body(base) |
             expr_do_body(base) => {
                 self.use_expr(base, comp_mode, visitor);
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 1b7cdf3ac80..ed3dfdc07c3 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -528,33 +528,6 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
             return src_datum.store_to_datum(
                 bcx, src.id, DROP_EXISTING, dst_datum);
         }
-        ast::expr_swap(dst, src) => {
-            let dst_datum = unpack_datum!(bcx, trans_lvalue(bcx, dst));
-            let src_datum = unpack_datum!(bcx, trans_lvalue(bcx, src));
-
-            // If the source and destination are the same, then don't swap.
-            // Avoids performing an overlapping memcpy
-            let dst_datum_ref = dst_datum.to_ref_llval(bcx);
-            let src_datum_ref = src_datum.to_ref_llval(bcx);
-            let cmp = ICmp(bcx, lib::llvm::IntEQ,
-                           src_datum_ref,
-                           dst_datum_ref);
-
-            let swap_cx = base::sub_block(bcx, "swap");
-            let next_cx = base::sub_block(bcx, "next");
-
-            CondBr(bcx, cmp, next_cx.llbb, swap_cx.llbb);
-
-            let scratch = scratch_datum(swap_cx, dst_datum.ty, false);
-
-            let swap_cx = dst_datum.move_to_datum(swap_cx, INIT, scratch);
-            let swap_cx = src_datum.move_to_datum(swap_cx, INIT, dst_datum);
-            let swap_cx = scratch.move_to_datum(swap_cx, INIT, src_datum);
-
-            Br(swap_cx, next_cx.llbb);
-
-            return next_cx;
-        }
         ast::expr_assign_op(op, dst, src) => {
             return trans_assign_op(bcx, expr, op, dst, src);
         }
diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs
index cbad7bcb3a6..3c2738d3ae8 100644
--- a/src/librustc/middle/trans/type_use.rs
+++ b/src/librustc/middle/trans/type_use.rs
@@ -314,7 +314,7 @@ pub fn mark_for_expr(cx: Context, e: @expr) {
               }
           }
       }
-      expr_assign(val, _) | expr_swap(val, _) | expr_assign_op(_, val, _) |
+      expr_assign(val, _) | expr_assign_op(_, val, _) |
       expr_ret(Some(val)) => {
         node_type_needs(cx, use_repr, val.id);
       }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 737548ee868..829a1e399de 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3465,7 +3465,6 @@ pub fn expr_kind(tcx: ctxt,
         ast::expr_while(*) |
         ast::expr_loop(*) |
         ast::expr_assign(*) |
-        ast::expr_swap(*) |
         ast::expr_inline_asm(*) |
         ast::expr_assign_op(*) => {
             RvalueStmtExpr
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index baa28b64982..7c79693a8b2 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -2460,20 +2460,6 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
             fcx.write_nil(id);
         }
       }
-      ast::expr_swap(lhs, rhs) => {
-        check_assignment(fcx, lhs, rhs, id);
-        let lhs_ty = fcx.expr_ty(lhs);
-        let rhs_ty = fcx.expr_ty(rhs);
-        if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
-            fcx.write_error(id);
-        }
-        else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
-            fcx.write_bot(id);
-        }
-        else {
-            fcx.write_nil(id);
-        }
-      }
       ast::expr_if(cond, ref thn, elsopt) => {
         check_expr_has_type(fcx, cond, ty::mk_bool());
         check_then_else(fcx, thn, elsopt, id, expr.span);
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index 2274259f18c..55c1f03b330 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -1016,7 +1016,6 @@ pub mod guarantor {
             ast::expr_while(*) |
             ast::expr_loop(*) |
             ast::expr_assign(*) |
-            ast::expr_swap(*) |
             ast::expr_assign_op(*) |
             ast::expr_cast(*) |
             ast::expr_call(*) |
diff --git a/src/librusti/rusti.rc b/src/librusti/rusti.rc
index a8cd7f5f41c..836ca1cfa45 100644
--- a/src/librusti/rusti.rc
+++ b/src/librusti/rusti.rc
@@ -96,10 +96,6 @@ fn record(repl: Repl, blk: @ast::blk, intr: @token::ident_interner) -> Repl {
                         match expr.node {
                             ast::expr_assign(*) |
                             ast::expr_assign_op(*) |
-                            ast::expr_swap(*) => {
-                                pprust::print_stmt(pp, *stmt);
-                                writer.write_line(~"");
-                            }
                             _ => {}
                         }
                     }
diff --git a/src/libstd/deque.rs b/src/libstd/deque.rs
index 4eb359e48a8..c94acaa1f70 100644
--- a/src/libstd/deque.rs
+++ b/src/libstd/deque.rs
@@ -10,6 +10,8 @@
 
 //! A double-ended queue implemented as a circular buffer
 
+use core::util::replace;
+
 static initial_capacity: uint = 32u; // 2^5
 
 pub struct Deque<T> {
@@ -142,9 +144,7 @@ fn grow<T>(nelts: uint, lo: uint, elts: &mut [Option<T>]) -> ~[Option<T>] {
     let mut rv = ~[];
 
     do rv.grow_fn(nelts + 1) |i| {
-        let mut element = None;
-        element <-> elts[(lo + i) % nelts];
-        element
+        replace(&mut elts[(lo + i) % nelts], None)
     }
 
     rv
diff --git a/src/libstd/future.rs b/src/libstd/future.rs
index b1b2fa2cd28..ac23ea1a6e2 100644
--- a/src/libstd/future.rs
+++ b/src/libstd/future.rs
@@ -26,6 +26,7 @@ use core::cell::Cell;
 use core::comm::{PortOne, oneshot, send_one};
 use core::pipes::recv;
 use core::task;
+use core::util::replace;
 
 #[doc = "The future type"]
 #[cfg(stage0)]
@@ -77,8 +78,7 @@ pub impl<A> Future<A> {
                 }
             }
             {
-                let mut state = Evaluating;
-                self.state <-> state;
+                let state = replace(&mut self.state, Evaluating);
                 match state {
                     Forced(_) | Evaluating => fail!(~"Logic error."),
                     Pending(f) => {
@@ -108,8 +108,7 @@ pub impl<A> Future<A> {
                 }
             }
             {
-                let mut state = Evaluating;
-                self.state <-> state;
+                let state = replace(&mut self.state, Evaluating);
                 match state {
                     Forced(_) | Evaluating => fail!(~"Logic error."),
                     Pending(f) => {
diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs
index bdb93142472..ded632b29d9 100644
--- a/src/libstd/priority_queue.rs
+++ b/src/libstd/priority_queue.rs
@@ -11,6 +11,7 @@
 //! A priority queue implemented with a binary heap
 
 use core::old_iter::BaseIter;
+use core::util::{replace, swap};
 
 #[abi = "rust-intrinsic"]
 extern "rust-intrinsic" mod rusti {
@@ -73,7 +74,10 @@ pub impl <T:Ord> PriorityQueue<T> {
     /// Pop the greatest item from the queue - fails if empty
     fn pop(&mut self) -> T {
         let mut item = self.data.pop();
-        if !self.is_empty() { item <-> self.data[0]; self.siftdown(0); }
+        if !self.is_empty() {
+            swap(&mut item, &mut self.data[0]);
+            self.siftdown(0);
+        }
         item
     }
 
@@ -92,7 +96,7 @@ pub impl <T:Ord> PriorityQueue<T> {
     /// Optimized version of a push followed by a pop
     fn push_pop(&mut self, mut item: T) -> T {
         if !self.is_empty() && self.data[0] > item {
-            item <-> self.data[0];
+            swap(&mut item, &mut self.data[0]);
             self.siftdown(0);
         }
         item
@@ -100,7 +104,7 @@ pub impl <T:Ord> PriorityQueue<T> {
 
     /// Optimized version of a pop followed by a push - fails if empty
     fn replace(&mut self, mut item: T) -> T {
-        item <-> self.data[0];
+        swap(&mut item, &mut self.data[0]);
         self.siftdown(0);
         item
     }
@@ -115,7 +119,7 @@ pub impl <T:Ord> PriorityQueue<T> {
         let mut end = q.len();
         while end > 1 {
             end -= 1;
-            q.data[end] <-> q.data[0];
+            vec::swap(q.data, 0, end);
             q.siftdown_range(0, end)
         }
         q.to_vec()
@@ -149,8 +153,7 @@ pub impl <T:Ord> PriorityQueue<T> {
             while pos > start {
                 let parent = (pos - 1) >> 1;
                 if new > self.data[parent] {
-                    let mut x = rusti::uninit();
-                    x <-> self.data[parent];
+                    let x = replace(&mut self.data[parent], rusti::uninit());
                     rusti::move_val_init(&mut self.data[pos], x);
                     pos = parent;
                     loop
@@ -169,8 +172,7 @@ pub impl <T:Ord> PriorityQueue<T> {
             while pos > start {
                 let parent = (pos - 1) >> 1;
                 if new > self.data[parent] {
-                    let mut x = rusti::init();
-                    x <-> self.data[parent];
+                    let x = replace(&mut self.data[parent], rusti::init());
                     rusti::move_val_init(&mut self.data[pos], x);
                     pos = parent;
                     loop
@@ -194,8 +196,7 @@ pub impl <T:Ord> PriorityQueue<T> {
                 if right < end && !(self.data[child] > self.data[right]) {
                     child = right;
                 }
-                let mut x = rusti::uninit();
-                x <-> self.data[child];
+                let x = replace(&mut self.data[child], rusti::uninit());
                 rusti::move_val_init(&mut self.data[pos], x);
                 pos = child;
                 child = 2 * pos + 1;
@@ -218,8 +219,7 @@ pub impl <T:Ord> PriorityQueue<T> {
                 if right < end && !(self.data[child] > self.data[right]) {
                     child = right;
                 }
-                let mut x = rusti::init();
-                x <-> self.data[child];
+                let x = replace(&mut self.data[child], rusti::init());
                 rusti::move_val_init(&mut self.data[pos], x);
                 pos = child;
                 child = 2 * pos + 1;
diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs
index 9eab1adde47..0c0f11fc9f0 100644
--- a/src/libstd/rc.rs
+++ b/src/libstd/rc.rs
@@ -17,6 +17,7 @@ destruction. They are restricted to containing `Owned` types in order to prevent
 
 use core::libc::{c_void, size_t, malloc, free};
 use core::unstable::intrinsics;
+use core::util;
 
 struct RcBox<T> {
     value: T,
@@ -52,8 +53,7 @@ impl<T: Owned> Drop for Rc<T> {
         unsafe {
             (*self.ptr).count -= 1;
             if (*self.ptr).count == 0 {
-                let mut x = intrinsics::uninit();
-                x <-> *self.ptr;
+                util::replace_ptr(self.ptr, intrinsics::uninit());
                 free(self.ptr as *c_void)
             }
         }
@@ -67,8 +67,7 @@ impl<T: Owned> Drop for Rc<T> {
         unsafe {
             (*self.ptr).count -= 1;
             if (*self.ptr).count == 0 {
-                let mut x = intrinsics::init();
-                x <-> *self.ptr;
+                util::replace_ptr(self.ptr, intrinsics::init());
                 free(self.ptr as *c_void)
             }
         }
@@ -111,13 +110,6 @@ mod test_rc {
     }
 }
 
-#[abi = "rust-intrinsic"]
-extern "rust-intrinsic" mod rusti {
-    fn init<T>() -> T;
-    #[cfg(not(stage0))]
-    fn uninit<T>() -> T;
-}
-
 #[deriving(Eq)]
 enum Borrow {
     Mutable,
@@ -179,8 +171,7 @@ impl<T: Owned> Drop for RcMut<T> {
         unsafe {
             (*self.ptr).count -= 1;
             if (*self.ptr).count == 0 {
-                let mut x = rusti::uninit();
-                x <-> *self.ptr;
+                util::replace_ptr(self.ptr, intrinsics::uninit());
                 free(self.ptr as *c_void)
             }
         }
@@ -194,8 +185,7 @@ impl<T: Owned> Drop for RcMut<T> {
         unsafe {
             (*self.ptr).count -= 1;
             if (*self.ptr).count == 0 {
-                let mut x = rusti::init();
-                x <-> *self.ptr;
+                util::replace_ptr(self.ptr, intrinsics::init());
                 free(self.ptr as *c_void)
             }
         }
diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs
index fdc74be1335..876eb716a38 100644
--- a/src/libstd/sort.rs
+++ b/src/libstd/sort.rs
@@ -13,6 +13,7 @@
 use core::cmp::{Eq, Ord};
 use core::vec::len;
 use core::vec;
+use core::util::swap;
 
 type Le<'self, T> = &'self fn(v1: &T, v2: &T) -> bool;
 
@@ -63,36 +64,36 @@ pub fn merge_sort<T:Copy>(v: &[T], le: Le<T>) -> ~[T] {
 #[cfg(stage0)]
 fn part<T>(arr: &mut [T], left: uint,
            right: uint, pivot: uint, compare_func: Le<T>) -> uint {
-    arr[pivot] <-> arr[right];
+    swap(&mut arr[pivot], &mut arr[right]);
     let mut storage_index: uint = left;
     let mut i: uint = left;
     while i < right {
         let a: &mut T = &mut arr[i];
         let b: &mut T = &mut arr[right];
         if compare_func(a, b) {
-            arr[i] <-> arr[storage_index];
+            swap(&mut arr[i], &mut arr[storage_index]);
             storage_index += 1;
         }
         i += 1;
     }
-    arr[storage_index] <-> arr[right];
+    swap(&mut arr[storage_index], &mut arr[right]);
     return storage_index;
 }
 
 #[cfg(not(stage0))]
 fn part<T>(arr: &mut [T], left: uint,
            right: uint, pivot: uint, compare_func: Le<T>) -> uint {
-    arr[pivot] <-> arr[right];
+    vec::swap(arr, pivot, right);
     let mut storage_index: uint = left;
     let mut i: uint = left;
     while i < right {
         if compare_func(&arr[i], &arr[right]) {
-            arr[i] <-> arr[storage_index];
+            vec::swap(arr, i, storage_index);
             storage_index += 1;
         }
         i += 1;
     }
-    arr[storage_index] <-> arr[right];
+    vec::swap(arr, storage_index, right);
     return storage_index;
 }
 
@@ -136,29 +137,29 @@ fn qsort3<T:Copy + Ord + Eq>(arr: &mut [T], left: int, right: int) {
             j -= 1;
         }
         if i >= j { break; }
-        arr[i] <-> arr[j];
+        vec::swap(arr, i as uint, j as uint);
         if arr[i] == v {
             p += 1;
-            arr[p] <-> arr[i];
+            vec::swap(arr, p as uint, i as uint);
         }
         if v == arr[j] {
             q -= 1;
-            arr[j] <-> arr[q];
+            vec::swap(arr, j as uint, q as uint);
         }
     }
-    arr[i] <-> arr[right];
+    vec::swap(arr, i as uint, right as uint);
     j = i - 1;
     i += 1;
     let mut k: int = left;
     while k < p {
-        arr[k] <-> arr[j];
+        vec::swap(arr, k as uint, j as uint);
         k += 1;
         j -= 1;
         if k == len::<T>(arr) as int { break; }
     }
     k = right - 1;
     while k > q {
-        arr[i] <-> arr[k];
+        vec::swap(arr, i as uint, k as uint);
         k -= 1;
         i += 1;
         if k == 0 { break; }
@@ -273,7 +274,7 @@ fn binarysort<T:Copy + Ord>(array: &mut [T], start: uint) {
 fn reverse_slice<T>(v: &mut [T], start: uint, end:uint) {
     let mut i = start;
     while i < end / 2 {
-        v[i] <-> v[end - i - 1];
+        vec::swap(v, i, end - i - 1);
         i += 1;
     }
 }
@@ -493,7 +494,7 @@ impl<T:Copy + Ord> MergeState<T> {
         let mut len1 = len1;
         let mut len2 = len2;
 
-        array[dest] <-> array[c2];
+        vec::swap(array, dest, c2);
         dest += 1; c2 += 1; len2 -= 1;
 
         if len2 == 0 {
@@ -502,7 +503,7 @@ impl<T:Copy + Ord> MergeState<T> {
         }
         if len1 == 1 {
             shift_vec(array, dest, c2, len2);
-            array[dest+len2] <-> tmp[c1];
+            swap(&mut tmp[c1], &mut array[dest+len2]);
             return;
         }
 
@@ -515,14 +516,14 @@ impl<T:Copy + Ord> MergeState<T> {
             loop {
                 assert!(len1 > 1 && len2 != 0);
                 if array[c2] < tmp[c1] {
-                    array[dest] <-> array[c2];
+                    vec::swap(array, dest, c2);
                     dest += 1; c2 += 1; len2 -= 1;
                     count2 += 1; count1 = 0;
                     if len2 == 0 {
                         break_outer = true;
                     }
                 } else {
-                    array[dest] <-> tmp[c1];
+                    swap(&mut array[dest], &mut tmp[c1]);
                     dest += 1; c1 += 1; len1 -= 1;
                     count1 += 1; count2 = 0;
                     if len1 == 1 {
@@ -548,7 +549,7 @@ impl<T:Copy + Ord> MergeState<T> {
                     dest += count1; c1 += count1; len1 -= count1;
                     if len1 <= 1 { break_outer = true; break; }
                 }
-                array[dest] <-> array[c2];
+                vec::swap(array, dest, c2);
                 dest += 1; c2 += 1; len2 -= 1;
                 if len2 == 0 { break_outer = true; break; }
 
@@ -561,7 +562,7 @@ impl<T:Copy + Ord> MergeState<T> {
                     dest += count2; c2 += count2; len2 -= count2;
                     if len2 == 0 { break_outer = true; break; }
                 }
-                array[dest] <-> tmp[c1];
+                swap(&mut array[dest], &mut tmp[c1]);
                 dest += 1; c1 += 1; len1 -= 1;
                 if len1 == 1 { break_outer = true; break; }
                 min_gallop -= 1;
@@ -578,7 +579,7 @@ impl<T:Copy + Ord> MergeState<T> {
         if len1 == 1 {
             assert!(len2 > 0);
             shift_vec(array, dest, c2, len2);
-            array[dest+len2] <-> tmp[c1];
+            swap(&mut array[dest+len2], &mut tmp[c1]);
         } else if len1 == 0 {
             fail!(~"Comparison violates its contract!");
         } else {
@@ -603,7 +604,7 @@ impl<T:Copy + Ord> MergeState<T> {
         let mut len1 = len1;
         let mut len2 = len2;
 
-        array[dest] <-> array[c1];
+        vec::swap(array, dest, c1);
         dest -= 1; c1 -= 1; len1 -= 1;
 
         if len1 == 0 {
@@ -614,7 +615,7 @@ impl<T:Copy + Ord> MergeState<T> {
             dest -= len1;
             c1 -= len1;
             shift_vec(array, dest+1, c1+1, len1);
-            array[dest] <-> tmp[c2];
+            swap(&mut array[dest], &mut tmp[c2]);
             return;
         }
 
@@ -627,14 +628,14 @@ impl<T:Copy + Ord> MergeState<T> {
             loop {
                 assert!(len1 != 0 && len2 > 1);
                 if tmp[c2] < array[c1] {
-                    array[dest] <-> array[c1];
+                    vec::swap(array, dest, c1);
                     dest -= 1; c1 -= 1; len1 -= 1;
                     count1 += 1; count2 = 0;
                     if len1 == 0 {
                         break_outer = true;
                     }
                 } else {
-                    array[dest] <-> tmp[c2];
+                    swap(&mut array[dest], &mut tmp[c2]);
                     dest -= 1; c2 -= 1; len2 -= 1;
                     count2 += 1; count1 = 0;
                     if len2 == 1 {
@@ -663,7 +664,7 @@ impl<T:Copy + Ord> MergeState<T> {
                     if len1 == 0 { break_outer = true; break; }
                 }
 
-                array[dest] <-> tmp[c2];
+                swap(&mut array[dest], &mut tmp[c2]);
                 dest -= 1; c2 -= 1; len2 -= 1;
                 if len2 == 1 { break_outer = true; break; }
 
@@ -680,7 +681,7 @@ impl<T:Copy + Ord> MergeState<T> {
                     copy_vec(array, dest+1, tmp.slice(c2+1, c2+1+count2));
                     if len2 <= 1 { break_outer = true; break; }
                 }
-                array[dest] <-> array[c1];
+                vec::swap(array, dest, c1);
                 dest -= 1; c1 -= 1; len1 -= 1;
                 if len1 == 0 { break_outer = true; break; }
                 min_gallop -= 1;
@@ -700,7 +701,7 @@ impl<T:Copy + Ord> MergeState<T> {
             dest -= len1;
             c1 -= len1;
             shift_vec(array, dest+1, c1+1, len1);
-            array[dest] <-> tmp[c2];
+            swap(&mut array[dest], &mut tmp[c2]);
         } else if len2 == 0 {
             fail!(~"Comparison violates its contract!");
         } else {
@@ -1090,7 +1091,7 @@ mod big_tests {
             for 3.times {
                 let i1 = rng.gen_uint_range(0, n);
                 let i2 = rng.gen_uint_range(0, n);
-                arr[i1] <-> arr[i2];
+                vec::swap(arr, i1, i2);
             }
             tim_sort(arr); // 3sort
             isSorted(arr);
@@ -1162,7 +1163,7 @@ mod big_tests {
             for 3.times {
                 let i1 = rng.gen_uint_range(0, n);
                 let i2 = rng.gen_uint_range(0, n);
-                arr[i1] <-> arr[i2];
+                vec::swap(arr, i1, i2);
             }
             tim_sort(arr); // 3sort
             isSorted(arr);
diff --git a/src/libstd/sort_stage0.rs b/src/libstd/sort_stage0.rs
index 2379e4617aa..00bd325dd0c 100644
--- a/src/libstd/sort_stage0.rs
+++ b/src/libstd/sort_stage0.rs
@@ -13,6 +13,7 @@
 use core::cmp::{Eq, Ord};
 use core::vec::len;
 use core::vec;
+use core::util;
 
 type Le<'self, T> = &'self fn(v1: &T, v2: &T) -> bool;
 
@@ -63,36 +64,36 @@ pub fn merge_sort<T:Copy>(v: &const [T], le: Le<T>) -> ~[T] {
 #[cfg(stage0)]
 fn part<T>(arr: &mut [T], left: uint,
            right: uint, pivot: uint, compare_func: Le<T>) -> uint {
-    arr[pivot] <-> arr[right];
+    vec::swap(arr, pivot, right);
     let mut storage_index: uint = left;
     let mut i: uint = left;
     while i < right {
         let a: &mut T = &mut arr[i];
         let b: &mut T = &mut arr[right];
         if compare_func(a, b) {
-            arr[i] <-> arr[storage_index];
+            vec::swap(arr, i, storage_index);
             storage_index += 1;
         }
         i += 1;
     }
-    arr[storage_index] <-> arr[right];
+    vec::swap(arr, storage_index, right);
     return storage_index;
 }
 
 #[cfg(not(stage0))]
 fn part<T>(arr: &mut [T], left: uint,
            right: uint, pivot: uint, compare_func: Le<T>) -> uint {
-    arr[pivot] <-> arr[right];
+    vec::swap(arr, pivot, right);
     let mut storage_index: uint = left;
     let mut i: uint = left;
     while i < right {
         if compare_func(&arr[i], &arr[right]) {
-            arr[i] <-> arr[storage_index];
+            vec::swap(arr, i, storage_index);
             storage_index += 1;
         }
         i += 1;
     }
-    arr[storage_index] <-> arr[right];
+    vec::swap(arr, storage_index, right);
     return storage_index;
 }
 
@@ -136,29 +137,29 @@ fn qsort3<T:Copy + Ord + Eq>(arr: &mut [T], left: int, right: int) {
             j -= 1;
         }
         if i >= j { break; }
-        arr[i] <-> arr[j];
+        vec::swap(arr, i as uint, j as uint);
         if arr[i] == v {
             p += 1;
-            arr[p] <-> arr[i];
+            vec::swap(arr, p as uint, i as uint);
         }
         if v == arr[j] {
             q -= 1;
-            arr[j] <-> arr[q];
+            vec::swap(arr, j as uint, q as uint);
         }
     }
-    arr[i] <-> arr[right];
+    vec::swap(arr, i as uint, right as uint);
     j = i - 1;
     i += 1;
     let mut k: int = left;
     while k < p {
-        arr[k] <-> arr[j];
+        vec::swap(arr, k as uint, j as uint);
         k += 1;
         j -= 1;
         if k == len::<T>(arr) as int { break; }
     }
     k = right - 1;
     while k > q {
-        arr[i] <-> arr[k];
+        vec::swap(arr, i as uint, k as uint);
         k -= 1;
         i += 1;
         if k == 0 { break; }
@@ -273,7 +274,7 @@ fn binarysort<T:Copy + Ord>(array: &mut [T], start: uint) {
 fn reverse_slice<T>(v: &mut [T], start: uint, end:uint) {
     let mut i = start;
     while i < end / 2 {
-        v[i] <-> v[end - i - 1];
+        vec::swap(v, i, end - i - 1);
         i += 1;
     }
 }
@@ -493,7 +494,7 @@ impl<T:Copy + Ord> MergeState<T> {
         let mut len1 = len1;
         let mut len2 = len2;
 
-        array[dest] <-> array[c2];
+        vec::swap(array, dest, c2);
         dest += 1; c2 += 1; len2 -= 1;
 
         if len2 == 0 {
@@ -502,7 +503,7 @@ impl<T:Copy + Ord> MergeState<T> {
         }
         if len1 == 1 {
             copy_vec(array, dest, array, c2, len2);
-            array[dest+len2] <-> tmp[c1];
+            util::swap(&mut array[dest+len2], &mut tmp[c1]);
             return;
         }
 
@@ -515,14 +516,14 @@ impl<T:Copy + Ord> MergeState<T> {
             loop {
                 assert!(len1 > 1 && len2 != 0);
                 if array[c2] < tmp[c1] {
-                    array[dest] <-> array[c2];
+                    vec::swap(array, dest, c2);
                     dest += 1; c2 += 1; len2 -= 1;
                     count2 += 1; count1 = 0;
                     if len2 == 0 {
                         break_outer = true;
                     }
                 } else {
-                    array[dest] <-> tmp[c1];
+                    util::swap(&mut array[dest], &mut tmp[c1]);
                     dest += 1; c1 += 1; len1 -= 1;
                     count1 += 1; count2 = 0;
                     if len1 == 1 {
@@ -546,7 +547,7 @@ impl<T:Copy + Ord> MergeState<T> {
                     dest += count1; c1 += count1; len1 -= count1;
                     if len1 <= 1 { break_outer = true; break; }
                 }
-                array[dest] <-> array[c2];
+                vec::swap(array, dest, c2);
                 dest += 1; c2 += 1; len2 -= 1;
                 if len2 == 0 { break_outer = true; break; }
 
@@ -557,7 +558,7 @@ impl<T:Copy + Ord> MergeState<T> {
                     dest += count2; c2 += count2; len2 -= count2;
                     if len2 == 0 { break_outer = true; break; }
                 }
-                array[dest] <-> tmp[c1];
+                util::swap(&mut array[dest], &mut tmp[c1]);
                 dest += 1; c1 += 1; len1 -= 1;
                 if len1 == 1 { break_outer = true; break; }
                 min_gallop -= 1;
@@ -574,7 +575,7 @@ impl<T:Copy + Ord> MergeState<T> {
         if len1 == 1 {
             assert!(len2 > 0);
             copy_vec(array, dest, array, c2, len2);
-            array[dest+len2] <-> tmp[c1];
+            util::swap(&mut array[dest+len2], &mut tmp[c1]);
         } else if len1 == 0 {
             fail!(~"Comparison violates its contract!");
         } else {
@@ -599,7 +600,7 @@ impl<T:Copy + Ord> MergeState<T> {
         let mut len1 = len1;
         let mut len2 = len2;
 
-        array[dest] <-> array[c1];
+        vec::swap(array, dest, c1);
         dest -= 1; c1 -= 1; len1 -= 1;
 
         if len1 == 0 {
@@ -610,7 +611,7 @@ impl<T:Copy + Ord> MergeState<T> {
             dest -= len1;
             c1 -= len1;
             copy_vec(array, dest+1, array, c1+1, len1);
-            array[dest] <-> tmp[c2];
+            util::swap(&mut array[dest], &mut tmp[c2]);
             return;
         }
 
@@ -623,14 +624,14 @@ impl<T:Copy + Ord> MergeState<T> {
             loop {
                 assert!(len1 != 0 && len2 > 1);
                 if tmp[c2] < array[c1] {
-                    array[dest] <-> array[c1];
+                    vec::swap(array, dest, c1);
                     dest -= 1; c1 -= 1; len1 -= 1;
                     count1 += 1; count2 = 0;
                     if len1 == 0 {
                         break_outer = true;
                     }
                 } else {
-                    array[dest] <-> tmp[c2];
+                    util::swap(&mut array[dest], &mut tmp[c2]);
                     dest -= 1; c2 -= 1; len2 -= 1;
                     count2 += 1; count1 = 0;
                     if len2 == 1 {
@@ -659,7 +660,7 @@ impl<T:Copy + Ord> MergeState<T> {
                     if len1 == 0 { break_outer = true; break; }
                 }
 
-                array[dest] <-> tmp[c2];
+                util::swap(&mut array[dest], &mut tmp[c2]);
                 dest -= 1; c2 -= 1; len2 -= 1;
                 if len2 == 1 { break_outer = true; break; }
 
@@ -676,7 +677,7 @@ impl<T:Copy + Ord> MergeState<T> {
                     copy_vec(array, dest+1, tmp, c2+1, count2);
                     if len2 <= 1 { break_outer = true; break; }
                 }
-                array[dest] <-> array[c1];
+                vec::swap(array, dest, c1);
                 dest -= 1; c1 -= 1; len1 -= 1;
                 if len1 == 0 { break_outer = true; break; }
                 min_gallop -= 1;
@@ -696,7 +697,7 @@ impl<T:Copy + Ord> MergeState<T> {
             dest -= len1;
             c1 -= len1;
             copy_vec(array, dest+1, array, c1+1, len1);
-            array[dest] <-> tmp[c2];
+            util::swap(&mut array[dest], &mut tmp[c2]);
         } else if len2 == 0 {
             fail!(~"Comparison violates its contract!");
         } else {
@@ -1081,7 +1082,7 @@ mod big_tests {
             for 3.times {
                 let i1 = rng.gen_uint_range(0, n);
                 let i2 = rng.gen_uint_range(0, n);
-                arr[i1] <-> arr[i2];
+                vec::swap(arr, i1, i2);
             }
             tim_sort(arr); // 3sort
             isSorted(arr);
@@ -1153,7 +1154,7 @@ mod big_tests {
             for 3.times {
                 let i1 = rng.gen_uint_range(0, n);
                 let i2 = rng.gen_uint_range(0, n);
-                arr[i1] <-> arr[i2];
+                vec::swap(arr, i1, i2);
             }
             tim_sort(arr); // 3sort
             isSorted(arr);
diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs
index 252bb1a6af8..2b39458d32d 100644
--- a/src/libstd/treemap.rs
+++ b/src/libstd/treemap.rs
@@ -13,7 +13,7 @@
 //! `TotalOrd`.
 
 use core::iterator::*;
-use core::util::replace;
+use core::util::{swap, replace};
 
 // This is implemented as an AA tree, which is a simplified variation of
 // a red-black tree where where red (horizontal) nodes can only be added
@@ -756,8 +756,8 @@ fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode<K, V>>,
 fn skew<K: TotalOrd, V>(node: &mut ~TreeNode<K, V>) {
     if node.left.map_default(false, |x| x.level == node.level) {
         let mut save = node.left.swap_unwrap();
-        node.left <-> save.right; // save.right now None
-        *node <-> save;
+        swap(&mut node.left, &mut save.right); // save.right now None
+        swap(node, &mut save);
         node.right = Some(save);
     }
 }
@@ -768,9 +768,9 @@ fn split<K: TotalOrd, V>(node: &mut ~TreeNode<K, V>) {
     if node.right.map_default(false,
       |x| x.right.map_default(false, |y| y.level == node.level)) {
         let mut save = node.right.swap_unwrap();
-        node.right <-> save.left; // save.left now None
+        swap(&mut node.right, &mut save.left); // save.left now None
         save.level += 1;
-        *node <-> save;
+        swap(node, &mut save);
         node.left = Some(save);
     }
 }
@@ -823,14 +823,14 @@ fn insert<K: TotalOrd, V>(node: &mut Option<~TreeNode<K, V>>,
 fn remove<K: TotalOrd, V>(node: &mut Option<~TreeNode<K, V>>,
                           key: &K) -> Option<V> {
     fn heir_swap<K: TotalOrd, V>(node: &mut ~TreeNode<K, V>,
-                            child: &mut Option<~TreeNode<K, V>>) {
+                                 child: &mut Option<~TreeNode<K, V>>) {
         // *could* be done without recursion, but it won't borrow check
         for child.each_mut |x| {
             if x.right.is_some() {
                 heir_swap(node, &mut x.right);
             } else {
-                node.key <-> x.key;
-                node.value <-> x.value;
+                swap(&mut node.key, &mut x.key);
+                swap(&mut node.value, &mut x.value);
             }
         }
     }
@@ -850,8 +850,8 @@ fn remove<K: TotalOrd, V>(node: &mut Option<~TreeNode<K, V>>,
                     if left.right.is_some() {
                         heir_swap(save, &mut left.right);
                     } else {
-                        save.key <-> left.key;
-                        save.value <-> left.value;
+                        swap(&mut save.key, &mut left.key);
+                        swap(&mut save.value, &mut left.value);
                     }
                     save.left = Some(left);
                     (remove(&mut save.left, key), true)
diff --git a/src/libstd/workcache.rs b/src/libstd/workcache.rs
index 9b0a6cb6226..a9e4ec50c7c 100644
--- a/src/libstd/workcache.rs
+++ b/src/libstd/workcache.rs
@@ -22,6 +22,7 @@ use core::io;
 use core::pipes::recv;
 use core::run;
 use core::to_bytes;
+use core::util::replace;
 
 /**
 *
@@ -352,9 +353,7 @@ impl TPrep for Prep {
 
             _ => {
                 let (port, chan) = oneshot();
-                let mut blk = None;
-                blk <-> bo;
-                let blk = blk.unwrap();
+                let blk = replace(&mut bo, None).unwrap();
                 let chan = Cell(chan);
 
                 do task::spawn {
@@ -386,9 +385,7 @@ fn unwrap<T:Owned +
             Decodable<json::Decoder>>( // FIXME(#5121)
         w: Work<T>) -> T {
     let mut ww = w;
-    let mut s = None;
-
-    ww.res <-> s;
+    let s = replace(&mut ww.res, None);
 
     match s {
         None => fail!(),
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index f4e3e683229..8aa59fd1775 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -569,7 +569,6 @@ pub enum expr_ {
 
     expr_copy(@expr),
     expr_assign(@expr, @expr),
-    expr_swap(@expr, @expr),
     expr_assign_op(binop, @expr, @expr),
     expr_field(@expr, ident, ~[@Ty]),
     expr_index(@expr, @expr),
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index d181dd87e38..338b9b29f00 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -511,9 +511,6 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ {
         expr_assign(el, er) => {
             expr_assign(fld.fold_expr(el), fld.fold_expr(er))
         }
-        expr_swap(el, er) => {
-            expr_swap(fld.fold_expr(el), fld.fold_expr(er))
-        }
         expr_assign_op(op, el, er) => {
             expr_assign_op(op, fld.fold_expr(el), fld.fold_expr(er))
         }
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index a4ac038cf46..e9e5bdfe13d 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -40,6 +40,7 @@ pub enum ObsoleteSyntax {
     ObsoleteModeInFnType,
     ObsoleteMoveInit,
     ObsoleteBinaryMove,
+    ObsoleteSwap,
     ObsoleteUnsafeBlock,
     ObsoleteUnenforcedBound,
     ObsoleteImplSyntax,
@@ -129,6 +130,10 @@ pub impl Parser {
                 "binary move",
                 "Write `foo = move bar` instead"
             ),
+            ObsoleteSwap => (
+                "swap",
+                "Use core::util::{swap, replace} instead"
+            ),
             ObsoleteUnsafeBlock => (
                 "non-standalone unsafe block",
                 "use an inner `unsafe { ... }` block instead"
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 3ddc7a87924..5aa45ab3c9b 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -26,7 +26,7 @@ use ast::{expr_break, expr_call, expr_cast, expr_copy, expr_do_body};
 use ast::{expr_field, expr_fn_block, expr_if, expr_index};
 use ast::{expr_lit, expr_log, expr_loop, expr_loop_body, expr_mac};
 use ast::{expr_method_call, expr_paren, expr_path, expr_repeat};
-use ast::{expr_ret, expr_swap, expr_struct, expr_tup, expr_unary};
+use ast::{expr_ret, expr_struct, expr_tup, expr_unary};
 use ast::{expr_vec, expr_vstore, expr_vstore_mut_box};
 use ast::{expr_vstore_slice, expr_vstore_box};
 use ast::{expr_vstore_mut_slice, expr_while, extern_fn, field, fn_decl};
@@ -70,7 +70,7 @@ use parse::lexer::reader;
 use parse::lexer::TokenAndSpan;
 use parse::obsolete::{ObsoleteClassTraits};
 use parse::obsolete::{ObsoleteLet, ObsoleteFieldTerminator};
-use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove};
+use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove, ObsoleteSwap};
 use parse::obsolete::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds};
 use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax};
 use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer};
@@ -1849,9 +1849,11 @@ pub impl Parser {
                            expr_break(None))
           }
           token::DARROW => {
+            self.obsolete(*self.span, ObsoleteSwap);
             self.bump();
-            let rhs = self.parse_expr();
-            self.mk_expr(lo, rhs.span.hi, expr_swap(lhs, rhs))
+            // Ignore what we get, this is an error anyway
+            self.parse_expr();
+            self.mk_expr(lo, self.span.hi, expr_break(None))
           }
           _ => {
               lhs
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 81652f9c1a1..9d2927eb74f 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1328,12 +1328,6 @@ pub fn print_expr(s: @ps, expr: @ast::expr) {
         word_space(s, ~"=");
         print_expr(s, rhs);
       }
-      ast::expr_swap(lhs, rhs) => {
-        print_expr(s, lhs);
-        space(s.s);
-        word_space(s, ~"<->");
-        print_expr(s, rhs);
-      }
       ast::expr_assign_op(op, lhs, rhs) => {
         print_expr(s, lhs);
         space(s.s);
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 90dd49d6848..dcc94c92a88 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -516,10 +516,6 @@ pub fn visit_expr<E: Copy>(ex: @expr, e: E, v: vt<E>) {
             (v.visit_expr)(a, e, v);
         }
         expr_copy(a) => (v.visit_expr)(a, e, v),
-        expr_swap(a, b) => {
-            (v.visit_expr)(a, e, v);
-            (v.visit_expr)(b, e, v);
-        }
         expr_assign_op(_, a, b) => {
             (v.visit_expr)(b, e, v);
             (v.visit_expr)(a, e, v);
diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs
index 95a83af93d5..e6b3b3bbe20 100644
--- a/src/test/bench/core-std.rs
+++ b/src/test/bench/core-std.rs
@@ -14,6 +14,7 @@ extern mod std;
 
 use std::time::precise_time_s;
 use core::rand::RngUtil;
+use core::util;
 
 macro_rules! bench (
     ($id:ident) => (maybe_run_test(argv, stringify!($id).to_owned(), $id))
@@ -115,7 +116,7 @@ fn vec_push_all() {
             v.push_all(rv);
         }
         else {
-            v <-> rv;
+            util::swap(&mut v, &mut rv);
             v.push_all(rv);
         }
     }
diff --git a/src/test/bench/msgsend-ring-pipes.rs b/src/test/bench/msgsend-ring-pipes.rs
index aef5c18499a..f698b2c3c11 100644
--- a/src/test/bench/msgsend-ring-pipes.rs
+++ b/src/test/bench/msgsend-ring-pipes.rs
@@ -20,6 +20,7 @@ extern mod std;
 
 use core::cell::Cell;
 use core::pipes::recv;
+use core::util;
 use std::time;
 use std::future;
 
@@ -42,10 +43,8 @@ fn thread_ring(i: uint,
     // Send/Receive lots of messages.
     for uint::range(0, count) |j| {
         //error!("task %?, iter %?", i, j);
-        let mut num_chan2 = None;
-        let mut num_port2 = None;
-        num_chan2 <-> num_chan;
-        num_port2 <-> num_port;
+        let num_chan2 = util::replace(&mut num_chan, None);
+        let num_port2 = util::replace(&mut num_port, None);
         num_chan = Some(ring::client::num(num_chan2.unwrap(), i * j));
         let port = num_port2.unwrap();
         match recv(port) {
diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs
index d1f3dbf22ce..210bf5cb6de 100644
--- a/src/test/bench/shootout-k-nucleotide-pipes.rs
+++ b/src/test/bench/shootout-k-nucleotide-pipes.rs
@@ -17,6 +17,7 @@ use core::hashmap::HashMap;
 use core::io::ReaderUtil;
 use core::comm::{stream, Port, Chan};
 use core::cmp::Ord;
+use core::util;
 
 // given a map, print a sorted version of it
 fn sort_and_fmt(mm: &HashMap<~[u8], uint>, total: uint) -> ~str {
@@ -159,8 +160,7 @@ fn main() {
     let mut from_child = ~[];
     let to_child   = vec::mapi(sizes, |ii, sz| {
         let sz = *sz;
-        let mut stream = None;
-        stream <-> streams[ii];
+        let stream = util::replace(&mut streams[ii], None);
         let (from_child_, to_parent_) = stream.unwrap();
 
         from_child.push(from_child_);
diff --git a/src/test/compile-fail/liveness-assign-imm-local-in-swap.rs b/src/test/compile-fail/liveness-assign-imm-local-in-swap.rs
deleted file mode 100644
index 40ccfca919b..00000000000
--- a/src/test/compile-fail/liveness-assign-imm-local-in-swap.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn test1() {
-    let v: int;
-    let mut w: int;
-    v = 1; //~ NOTE prior assignment occurs here
-    w = 2;
-    v <-> w; //~ ERROR re-assignment of immutable variable
-}
-
-fn test2() {
-    let v: int;
-    let mut w: int;
-    v = 1; //~ NOTE prior assignment occurs here
-    w = 2;
-    w <-> v; //~ ERROR re-assignment of immutable variable
-}
-
-fn main() {
-}
diff --git a/src/test/compile-fail/liveness-swap-uninit.rs b/src/test/compile-fail/liveness-swap-uninit.rs
deleted file mode 100644
index b2d475dd789..00000000000
--- a/src/test/compile-fail/liveness-swap-uninit.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
-    let mut x = 3;
-    let y;
-    x <-> y; //~ ERROR use of possibly uninitialized variable: `y`
-    copy x;
-}
diff --git a/src/test/compile-fail/moves-based-on-type-exprs.rs b/src/test/compile-fail/moves-based-on-type-exprs.rs
index 7356c227360..5b733129ee5 100644
--- a/src/test/compile-fail/moves-based-on-type-exprs.rs
+++ b/src/test/compile-fail/moves-based-on-type-exprs.rs
@@ -87,7 +87,7 @@ fn f110() {
 
 fn f120() {
     let x = ~[~"hi", ~"ho"];
-    x[0] <-> x[1];
+    vec::swap(x, 0, 1);
     touch(&x[0]);
     touch(&x[1]);
 }
diff --git a/src/test/compile-fail/swap-no-lval.rs b/src/test/compile-fail/swap-no-lval.rs
deleted file mode 100644
index eca5fb0d315..00000000000
--- a/src/test/compile-fail/swap-no-lval.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
-    5 <-> 3;
-    //~^ ERROR cannot assign
-    //~^^ ERROR cannot assign
-}
diff --git a/src/test/run-pass/borrowck-mut-uniq.rs b/src/test/run-pass/borrowck-mut-uniq.rs
index 778637701c5..023eaae0a76 100644
--- a/src/test/run-pass/borrowck-mut-uniq.rs
+++ b/src/test/run-pass/borrowck-mut-uniq.rs
@@ -8,14 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use core::util;
+
 struct Ints {sum: ~int, values: ~[int]}
 
 fn add_int(x: &mut Ints, v: int) {
     *x.sum += v;
     let mut values = ~[];
-    x.values <-> values;
+    util::swap(&mut values, &mut x.values);
     values.push(v);
-    x.values <-> values;
+    util::swap(&mut values, &mut x.values);
 }
 
 fn iter_ints(x: &Ints, f: &fn(x: &int) -> bool) -> bool {
diff --git a/src/test/run-pass/issue-2718.rs b/src/test/run-pass/issue-2718.rs
index acd26a88a73..60daaea57d7 100644
--- a/src/test/run-pass/issue-2718.rs
+++ b/src/test/run-pass/issue-2718.rs
@@ -10,8 +10,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use core::util;
+
 // tjc: I don't know why
 pub mod pipes {
+    use core::util;
     use core::cast::{forget, transmute};
 
     pub struct Stuff<T> {
@@ -104,8 +107,7 @@ pub mod pipes {
             match old_state {
               empty | blocked => { task::yield(); }
               full => {
-                let mut payload = None;
-                payload <-> (*p).payload;
+                let payload = util::replace(&mut p.payload, None);
                 return Some(payload.unwrap())
               }
               terminated => {
@@ -159,10 +161,9 @@ pub mod pipes {
         fn finalize(&self) {
             unsafe {
                 if self.p != None {
-                    let mut p = None;
                     let self_p: &mut Option<*packet<T>> =
                         cast::transmute(&self.p);
-                    p <-> *self_p;
+                    let p = util::replace(self_p, None);
                     sender_terminate(p.unwrap())
                 }
             }
@@ -171,9 +172,7 @@ pub mod pipes {
 
     pub impl<T:Owned> send_packet<T> {
         fn unwrap(&mut self) -> *packet<T> {
-            let mut p = None;
-            p <-> self.p;
-            p.unwrap()
+            util::replace(&mut self.p, None).unwrap()
         }
     }
 
@@ -192,10 +191,9 @@ pub mod pipes {
         fn finalize(&self) {
             unsafe {
                 if self.p != None {
-                    let mut p = None;
                     let self_p: &mut Option<*packet<T>> =
                         cast::transmute(&self.p);
-                    p <-> *self_p;
+                    let p = util::replace(self_p, None);
                     receiver_terminate(p.unwrap())
                 }
             }
@@ -204,9 +202,7 @@ pub mod pipes {
 
     pub impl<T:Owned> recv_packet<T> {
         fn unwrap(&mut self) -> *packet<T> {
-            let mut p = None;
-            p <-> self.p;
-            p.unwrap()
+            util::replace(&mut self.p, None).unwrap()
         }
     }
 
@@ -225,6 +221,7 @@ pub mod pipes {
 pub mod pingpong {
     use core::cast;
     use core::ptr;
+    use core::util;
 
     pub struct ping(::pipes::send_packet<pong>);
     pub struct pong(::pipes::send_packet<ping>);
diff --git a/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs b/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs
index 39da08de6df..a87a899cafe 100644
--- a/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs
+++ b/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use core::util;
+
 pub fn main() {
     let mut x = 4;
 
@@ -24,6 +26,6 @@ pub fn main() {
             }
         }
         let mut y = 4;
-        y <-> x;
+        util::swap(&mut y, &mut x);
     }
 }
diff --git a/src/test/run-pass/swap-1.rs b/src/test/run-pass/swap-1.rs
index feb7a88dc34..ed69fa41d71 100644
--- a/src/test/run-pass/swap-1.rs
+++ b/src/test/run-pass/swap-1.rs
@@ -8,7 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use core::util;
+
 pub fn main() {
     let mut x = 3; let mut y = 7;
-    x <-> y; assert!((x == 7)); assert!((y == 3));
+    util::swap(&mut x, &mut y);
+    assert!((x == 7)); assert!((y == 3));
 }
diff --git a/src/test/run-pass/swap-2.rs b/src/test/run-pass/swap-2.rs
index 24794b03591..63b377b26d8 100644
--- a/src/test/run-pass/swap-2.rs
+++ b/src/test/run-pass/swap-2.rs
@@ -8,15 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn swap<T>(v: &mut [T], i: int, j: int) { v[i] <-> v[j]; }
+use core::util;
 
 pub fn main() {
     let mut a: ~[int] = ~[0, 1, 2, 3, 4, 5, 6];
-    swap(a, 2, 4);
+    vec::swap(a, 2, 4);
     assert!((a[2] == 4));
     assert!((a[4] == 2));
     let mut n = 42;
-    n <-> a[0];
+    util::swap(&mut n, &mut a[0]);
     assert!((a[0] == 42));
     assert!((n == 0));
 }
diff --git a/src/test/run-pass/swap-overlapping.rs b/src/test/run-pass/swap-overlapping.rs
index 90b2ceef71a..05f943bf928 100644
--- a/src/test/run-pass/swap-overlapping.rs
+++ b/src/test/run-pass/swap-overlapping.rs
@@ -10,6 +10,8 @@
 
 // Issue #5041 - avoid overlapping memcpy when src and dest of a swap are the same
 
+use core::util;
+
 pub fn main() {
     let mut test = TestDescAndFn {
         desc: TestDesc {
@@ -22,7 +24,10 @@ pub fn main() {
 }
 
 fn do_swap(test: &mut TestDescAndFn) {
-    *test <-> *test;
+    unsafe {
+        util::swap_ptr(ptr::to_mut_unsafe_ptr(test),
+                       ptr::to_mut_unsafe_ptr(test));
+    }
 }
 
 pub enum TestName {
diff --git a/src/test/run-pass/unique-swap.rs b/src/test/run-pass/unique-swap.rs
index 6cd7b358c55..bf58e2c7cb5 100644
--- a/src/test/run-pass/unique-swap.rs
+++ b/src/test/run-pass/unique-swap.rs
@@ -8,10 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use core::util;
+
 pub fn main() {
     let mut i = ~100;
     let mut j = ~200;
-    i <-> j;
+    util::swap(&mut i, &mut j);
     assert!(i == ~200);
     assert!(j == ~100);
 }
diff --git a/src/test/run-pass/weird-exprs.rs b/src/test/run-pass/weird-exprs.rs
index ed0032b93ea..38aa56b6512 100644
--- a/src/test/run-pass/weird-exprs.rs
+++ b/src/test/run-pass/weird-exprs.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use core::util;
+
 // Just a grab bag of stuff that you wouldn't want to actually write.
 
 fn strange() -> bool { let _x: bool = return true; }
@@ -52,7 +54,7 @@ fn notsure() {
     let mut _y = (_x = 0) == (_x = 0);
     let mut _z = (_x = 0) < (_x = 0);
     let _a = (_x += 0) == (_x = 0);
-    let _b = (_y <-> _z) == (_y <-> _z);
+    let _b = util::swap(&mut _y, &mut _z) == util::swap(&mut _y, &mut _z);
 }
 
 fn canttouchthis() -> uint {