about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/etc/vim/after/syntax/rust.vim4
-rw-r--r--src/etc/vim/syntax/rust.vim6
-rw-r--r--src/libcore/at_vec.rs28
-rw-r--r--src/libcore/cell.rs7
-rw-r--r--src/libcore/clone.rs102
-rw-r--r--src/libcore/hashmap.rs5
-rw-r--r--src/libcore/iter.rs106
-rw-r--r--src/libcore/num/f32.rs6
-rw-r--r--src/libcore/num/f64.rs6
-rw-r--r--src/libcore/num/float.rs8
-rw-r--r--src/libcore/num/num.rs10
-rw-r--r--src/libcore/option.rs10
-rw-r--r--src/libcore/os.rs37
-rw-r--r--src/libcore/prelude.rs2
-rw-r--r--src/libcore/rt/stack.rs4
-rw-r--r--src/libcore/rt/uv/mod.rs2
-rw-r--r--src/libcore/unstable/intrinsics.rs76
-rw-r--r--src/libcore/util.rs15
-rw-r--r--src/libcore/vec.rs171
-rw-r--r--src/librustc/README.txt8
-rw-r--r--src/librustc/back/link.rs1
-rw-r--r--src/librustc/driver/driver.rs7
-rw-r--r--src/librustc/driver/session.rs26
-rw-r--r--src/librustc/lib/llvm.rs1
-rw-r--r--src/librustc/metadata/csearch.rs11
-rw-r--r--src/librustc/metadata/decoder.rs11
-rw-r--r--src/librustc/metadata/tydecode.rs8
-rw-r--r--src/librustc/metadata/tyencode.rs5
-rw-r--r--src/librustc/middle/astencode.rs2
-rw-r--r--src/librustc/middle/borrowck/gather_loans/lifetime.rs15
-rw-r--r--src/librustc/middle/freevars.rs3
-rw-r--r--src/librustc/middle/lint.rs851
-rw-r--r--src/librustc/middle/liveness.rs29
-rw-r--r--src/librustc/middle/mem_categorization.rs2
-rw-r--r--src/librustc/middle/moves.rs6
-rw-r--r--src/librustc/middle/resolve.rs318
-rw-r--r--src/librustc/middle/resolve_stage0.rs19
-rw-r--r--src/librustc/middle/trans/base.rs3
-rw-r--r--src/librustc/middle/trans/build.rs2
-rw-r--r--src/librustc/middle/trans/datum.rs1
-rw-r--r--src/librustc/middle/trans/foreign.rs1
-rw-r--r--src/librustc/middle/trans/meth.rs7
-rw-r--r--src/librustc/middle/trans/monomorphize.rs1
-rw-r--r--src/librustc/middle/ty.rs85
-rw-r--r--src/librustc/middle/typeck/astconv.rs88
-rw-r--r--src/librustc/middle/typeck/check/mod.rs29
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs28
-rw-r--r--src/librustc/middle/typeck/coherence.rs8
-rw-r--r--src/librustc/middle/typeck/collect.rs20
-rw-r--r--src/librustc/middle/typeck/infer/combine.rs4
-rw-r--r--src/librustc/middle/typeck/infer/glb.rs7
-rw-r--r--src/librustc/middle/typeck/infer/lub.rs7
-rw-r--r--src/librustc/middle/typeck/infer/sub.rs14
-rw-r--r--src/librustc/middle/typeck/mod.rs6
-rw-r--r--src/librustc/util/enum_set.rs13
-rw-r--r--src/librustpkg/conditions.rs4
-rw-r--r--src/librustpkg/path_util.rs108
-rw-r--r--src/librustpkg/rustpkg.rc230
-rw-r--r--src/librustpkg/tests.rs95
-rw-r--r--src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/main.rs (renamed from src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/src/main.rs)0
-rw-r--r--src/librustpkg/testsuite/pass/src/external-crate/main.rs (renamed from src/librustpkg/testsuite/pass/src/external-crate/src/main.rs)0
-rw-r--r--src/librustpkg/util.rs288
-rw-r--r--src/librustpkg/workspace.rs7
-rw-r--r--src/libstd/ebml.rs2
-rw-r--r--src/libstd/json.rs12
-rw-r--r--src/libstd/rc.rs170
-rw-r--r--src/libstd/time.rs8
-rw-r--r--src/libstd/workcache.rs4
-rw-r--r--src/libsyntax/abi.rs4
-rw-r--r--src/libsyntax/ast.rs315
-rw-r--r--src/libsyntax/ast_util.rs10
-rw-r--r--src/libsyntax/codemap.rs4
-rw-r--r--src/libsyntax/ext/auto_encode.rs1486
-rw-r--r--src/libsyntax/ext/base.rs11
-rw-r--r--src/libsyntax/ext/build.rs301
-rw-r--r--src/libsyntax/ext/bytes.rs73
-rw-r--r--src/libsyntax/ext/deriving/clone.rs54
-rw-r--r--src/libsyntax/ext/deriving/cmp/eq.rs8
-rw-r--r--src/libsyntax/ext/deriving/decodable.rs5
-rw-r--r--src/libsyntax/ext/deriving/encodable.rs312
-rw-r--r--src/libsyntax/ext/deriving/iter_bytes.rs10
-rw-r--r--src/libsyntax/ext/deriving/mod.rs14
-rw-r--r--src/libsyntax/ext/quote.rs10
-rw-r--r--src/libsyntax/ext/trace_macros.rs4
-rw-r--r--src/libsyntax/fold.rs1
-rw-r--r--src/libsyntax/opt_vec.rs3
-rw-r--r--src/libsyntax/parse/common.rs42
-rw-r--r--src/libsyntax/parse/obsolete.rs4
-rw-r--r--src/libsyntax/parse/parser.rs227
-rw-r--r--src/libsyntax/parse/token.rs12
-rw-r--r--src/libsyntax/syntax.rc1
m---------src/libuv0
-rw-r--r--src/rustllvm/RustWrapper.cpp2
-rw-r--r--src/test/compile-fail/borrowck-rvalues-mutable-bad.rs38
-rw-r--r--src/test/compile-fail/closure-bounds-not-builtin.rs8
-rw-r--r--src/test/compile-fail/closure-bounds-subtype.rs34
-rw-r--r--src/test/compile-fail/deprecated-auto-code.rs (renamed from src/test/compile-fail/deriving-obsolete.rs)10
-rw-r--r--src/test/compile-fail/lint-impl-fn.rs37
-rw-r--r--src/test/compile-fail/lint-unused-imports.rs (renamed from src/test/compile-fail/unused-imports-warn.rs)0
-rw-r--r--src/test/compile-fail/lint-unused-mut-variables.rs (renamed from src/test/compile-fail/unused-mut-variables.rs)0
-rw-r--r--src/test/compile-fail/lint-unused-unsafe.rs (renamed from src/test/compile-fail/unused-unsafe.rs)0
-rw-r--r--src/test/compile-fail/liveness-dead.rs11
-rw-r--r--src/test/compile-fail/syntax-extension-bytes-non-ascii-char-literal.rs13
-rw-r--r--src/test/compile-fail/syntax-extension-bytes-non-literal.rs13
-rw-r--r--src/test/compile-fail/syntax-extension-bytes-too-large-integer-literal.rs13
-rw-r--r--src/test/compile-fail/syntax-extension-bytes-too-large-u8-literal.rs13
-rw-r--r--src/test/compile-fail/syntax-extension-bytes-too-small-integer-literal.rs13
-rw-r--r--src/test/compile-fail/syntax-extension-bytes-too-small-u8-literal.rs13
-rw-r--r--src/test/compile-fail/syntax-extension-bytes-unsupported-literal.rs13
-rw-r--r--src/test/run-pass/borrowck-rvalues-mutable.rs30
-rw-r--r--src/test/run-pass/deriving-clone-enum.rs7
-rw-r--r--src/test/run-pass/deriving-clone-generic-enum.rs17
-rw-r--r--src/test/run-pass/deriving-clone-generic-struct.rs6
-rw-r--r--src/test/run-pass/deriving-clone-generic-tuple-struct.rs16
-rw-r--r--src/test/run-pass/deriving-clone-struct.rs12
-rw-r--r--src/test/run-pass/issue-6130.rs20
-rw-r--r--src/test/run-pass/syntax-extension-bytes.rs24
117 files changed, 3153 insertions, 3301 deletions
diff --git a/src/etc/vim/after/syntax/rust.vim b/src/etc/vim/after/syntax/rust.vim
index 75afe3d0368..1ab8394e565 100644
--- a/src/etc/vim/after/syntax/rust.vim
+++ b/src/etc/vim/after/syntax/rust.vim
@@ -11,10 +11,6 @@ syn match rustRightArrowHead contained ">" conceal cchar= 
 syn match rustRightArrowTail contained "-" conceal cchar=⟶
 syn match rustNiceOperator "->" contains=rustRightArrowHead,rustRightArrowTail
 
-syn match rustLeftRightArrowHead contained ">" conceal cchar= 
-syn match rustLeftRightArrowTail contained "<-" conceal cchar=⟷
-syn match rustNiceOperator "<->" contains=rustLeftRightArrowHead,rustLeftRightArrowTail
-
 syn match rustFatRightArrowHead contained ">" conceal cchar= 
 syn match rustFatRightArrowTail contained "=" conceal cchar=⟹
 syn match rustNiceOperator "=>" contains=rustFatRightArrowHead,rustFatRightArrowTail
diff --git a/src/etc/vim/syntax/rust.vim b/src/etc/vim/syntax/rust.vim
index 3b5324f5cce..cd794df0a8d 100644
--- a/src/etc/vim/syntax/rust.vim
+++ b/src/etc/vim/syntax/rust.vim
@@ -15,7 +15,7 @@ syn keyword   rustOperator    as
 
 syn keyword   rustKeyword     break copy do drop extern
 syn keyword   rustKeyword     for if impl let log
-syn keyword   rustKeyword     copy do drop extern
+syn keyword   rustKeyword     copy do extern
 syn keyword   rustKeyword     for impl let log
 syn keyword   rustKeyword     loop mod once priv pub
 syn keyword   rustKeyword     return
@@ -28,8 +28,8 @@ syn keyword   rustStorage     const mut ref static
 syn match     rustIdentifier  contains=rustIdentifierPrime "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
 syn match     rustFuncName    "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
 
-" Reserved words
-"syn keyword   rustKeyword     m32 m64 m128 f80 f16 f128 be " These are obsolete
+" reserved
+syn keyword   rustKeyword     be
 
 syn keyword   rustType        int uint float char bool u8 u16 u32 u64 f32
 syn keyword   rustType        f64 i8 i16 i32 i64 str Self
diff --git a/src/libcore/at_vec.rs b/src/libcore/at_vec.rs
index d0f9a4ff90f..93bbf8fb662 100644
--- a/src/libcore/at_vec.rs
+++ b/src/libcore/at_vec.rs
@@ -149,7 +149,7 @@ pub fn from_elem<T:Copy>(n_elts: uint, t: T) -> @[T] {
  * Creates and initializes an immutable managed vector by moving all the
  * elements from an owned vector.
  */
-pub fn from_owned<T>(v: ~[T]) -> @[T] {
+pub fn to_managed_consume<T>(v: ~[T]) -> @[T] {
     let mut av = @[];
     unsafe {
         raw::reserve(&mut av, v.len());
@@ -164,7 +164,7 @@ pub fn from_owned<T>(v: ~[T]) -> @[T] {
  * Creates and initializes an immutable managed vector by copying all the
  * elements of a slice.
  */
-pub fn from_slice<T:Copy>(v: &[T]) -> @[T] {
+pub fn to_managed<T:Copy>(v: &[T]) -> @[T] {
     from_fn(v.len(), |i| v[i])
 }
 
@@ -304,20 +304,20 @@ mod test {
     }
 
     #[test]
-    fn test_from_owned() {
-        assert!(from_owned::<int>(~[]) == @[]);
-        assert!(from_owned(~[true]) == @[true]);
-        assert!(from_owned(~[1, 2, 3, 4, 5]) == @[1, 2, 3, 4, 5]);
-        assert!(from_owned(~[~"abc", ~"123"]) == @[~"abc", ~"123"]);
-        assert!(from_owned(~[~[42]]) == @[~[42]]);
+    fn test_to_managed_consume() {
+        assert!(to_managed_consume::<int>(~[]) == @[]);
+        assert!(to_managed_consume(~[true]) == @[true]);
+        assert!(to_managed_consume(~[1, 2, 3, 4, 5]) == @[1, 2, 3, 4, 5]);
+        assert!(to_managed_consume(~[~"abc", ~"123"]) == @[~"abc", ~"123"]);
+        assert!(to_managed_consume(~[~[42]]) == @[~[42]]);
     }
 
     #[test]
-    fn test_from_slice() {
-        assert!(from_slice::<int>([]) == @[]);
-        assert!(from_slice([true]) == @[true]);
-        assert!(from_slice([1, 2, 3, 4, 5]) == @[1, 2, 3, 4, 5]);
-        assert!(from_slice([@"abc", @"123"]) == @[@"abc", @"123"]);
-        assert!(from_slice([@[42]]) == @[@[42]]);
+    fn test_to_managed() {
+        assert!(to_managed::<int>([]) == @[]);
+        assert!(to_managed([true]) == @[true]);
+        assert!(to_managed([1, 2, 3, 4, 5]) == @[1, 2, 3, 4, 5]);
+        assert!(to_managed([@"abc", @"123"]) == @[@"abc", @"123"]);
+        assert!(to_managed([@[42]]) == @[@[42]]);
     }
 }
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index cacde5535db..87e8d0525e5 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -21,10 +21,17 @@ Similar to a mutable option type, but friendlier.
 */
 
 #[mutable]
+#[deriving(Clone)]
 pub struct Cell<T> {
     priv value: Option<T>
 }
 
+impl<T: DeepClone> DeepClone for Cell<T> {
+    fn deep_clone(&self) -> Cell<T> {
+        Cell{value: self.value.deep_clone()}
+    }
+}
+
 impl<T:cmp::Eq> cmp::Eq for Cell<T> {
     fn eq(&self, other: &Cell<T>) -> bool {
         (self.value) == (other.value)
diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs
index 9da970918b0..4d2b5998b44 100644
--- a/src/libcore/clone.rs
+++ b/src/libcore/clone.rs
@@ -22,18 +22,15 @@ by convention implementing the `Clone` trait and calling the
 
 */
 
+use core::kinds::Const;
+
 pub trait Clone {
-    /// Return a deep copy of the owned object tree. Managed boxes are cloned with a shallow copy.
+    /// Return a deep copy of the owned object tree. Types with shared ownership like managed boxes
+    /// are cloned with a shallow copy.
     fn clone(&self) -> Self;
 }
 
-impl Clone for () {
-    /// Return a copy of the value.
-    #[inline(always)]
-    fn clone(&self) -> () { () }
-}
-
-impl<T:Clone> Clone for ~T {
+impl<T: Clone> Clone for ~T {
     /// Return a deep copy of the owned box.
     #[inline(always)]
     fn clone(&self) -> ~T { ~(**self).clone() }
@@ -51,10 +48,16 @@ impl<T> Clone for @mut T {
     fn clone(&self) -> @mut T { *self }
 }
 
+impl<'self, T> Clone for &'self T {
+    /// Return a shallow copy of the borrowed pointer.
+    #[inline(always)]
+    fn clone(&self) -> &'self T { *self }
+}
+
 macro_rules! clone_impl(
     ($t:ty) => {
         impl Clone for $t {
-            /// Return a copy of the value.
+            /// Return a deep copy of the value.
             #[inline(always)]
             fn clone(&self) -> $t { *self }
         }
@@ -77,28 +80,103 @@ clone_impl!(float)
 clone_impl!(f32)
 clone_impl!(f64)
 
+clone_impl!(())
 clone_impl!(bool)
 clone_impl!(char)
 
+pub trait DeepClone {
+    /// Return a deep copy of the object tree. Types with shared ownership are also copied via a
+    /// deep copy, unlike `Clone`.
+    fn deep_clone(&self) -> Self;
+}
+
+impl<T: DeepClone> DeepClone for ~T {
+    /// Return a deep copy of the owned box.
+    #[inline(always)]
+    fn deep_clone(&self) -> ~T { ~(**self).deep_clone() }
+}
+
+// FIXME: #6525: should also be implemented for `T: Owned + DeepClone`
+impl<T: Const + DeepClone> DeepClone for @T {
+    /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing
+    /// a deep clone of a potentially cyclical type.
+    #[inline(always)]
+    fn deep_clone(&self) -> @T { @(**self).deep_clone() }
+}
+
+// FIXME: #6525: should also be implemented for `T: Owned + DeepClone`
+impl<T: Const + DeepClone> DeepClone for @mut T {
+    /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing
+    /// a deep clone of a potentially cyclical type.
+    #[inline(always)]
+    fn deep_clone(&self) -> @mut T { @mut (**self).deep_clone() }
+}
+
+macro_rules! deep_clone_impl(
+    ($t:ty) => {
+        impl DeepClone for $t {
+            /// Return a deep copy of the value.
+            #[inline(always)]
+            fn deep_clone(&self) -> $t { *self }
+        }
+    }
+)
+
+deep_clone_impl!(int)
+deep_clone_impl!(i8)
+deep_clone_impl!(i16)
+deep_clone_impl!(i32)
+deep_clone_impl!(i64)
+
+deep_clone_impl!(uint)
+deep_clone_impl!(u8)
+deep_clone_impl!(u16)
+deep_clone_impl!(u32)
+deep_clone_impl!(u64)
+
+deep_clone_impl!(float)
+deep_clone_impl!(f32)
+deep_clone_impl!(f64)
+
+deep_clone_impl!(())
+deep_clone_impl!(bool)
+deep_clone_impl!(char)
+
 #[test]
 fn test_owned_clone() {
-    let a: ~int = ~5i;
+    let a = ~5i;
     let b: ~int = a.clone();
     assert!(a == b);
 }
 
 #[test]
 fn test_managed_clone() {
-    let a: @int = @5i;
+    let a = @5i;
     let b: @int = a.clone();
     assert!(a == b);
 }
 
 #[test]
+fn test_managed_mut_deep_clone() {
+    let x = @mut 5i;
+    let y: @mut int = x.deep_clone();
+    *x = 20;
+    assert_eq!(*y, 5);
+}
+
+#[test]
 fn test_managed_mut_clone() {
-    let a: @mut int = @mut 5i;
+    let a = @mut 5i;
     let b: @mut int = a.clone();
     assert!(a == b);
     *b = 10;
     assert!(a == b);
 }
+
+#[test]
+fn test_borrowed_clone() {
+    let x = 5i;
+    let y: &int = &x;
+    let z: &int = (&y).clone();
+    assert_eq!(*z, 5);
+}
diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs
index 264b2a78965..d9912813cf9 100644
--- a/src/libcore/hashmap.rs
+++ b/src/libcore/hashmap.rs
@@ -17,7 +17,6 @@ use container::{Container, Mutable, Map, Set};
 use cmp::{Eq, Equiv};
 use hash::Hash;
 use old_iter::BaseIter;
-use hash::Hash;
 use old_iter;
 use option::{None, Option, Some};
 use rand::RngUtil;
@@ -825,6 +824,10 @@ pub impl <T:Hash + Eq> HashSet<T> {
     fn consume(&mut self, f: &fn(T)) {
         self.map.consume(|k, _| f(k))
     }
+
+    fn contains_equiv<Q:Hash + Equiv<T>>(&self, value: &Q) -> bool {
+      self.map.contains_key_equiv(value)
+    }
 }
 
 #[cfg(test)]
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
index cfc9afb737c..ae4af3812d2 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -43,6 +43,8 @@ much easier to implement.
 #[cfg(not(stage0))] use cmp::Ord;
 #[cfg(not(stage0))] use option::{Option, Some, None};
 #[cfg(not(stage0))] use vec::OwnedVector;
+#[cfg(not(stage0))] use num::{One, Zero};
+#[cfg(not(stage0))] use ops::{Add, Mul};
 
 #[cfg(stage0)]
 pub trait Times {
@@ -212,6 +214,81 @@ pub fn min<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
     result
 }
 
+/**
+ * Reduce an iterator to an accumulated value.
+ *
+ * # Example:
+ *
+ * ~~~~
+ * assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10);
+ * ~~~~
+ */
+#[cfg(not(stage0))]
+#[inline]
+pub fn fold<T, U>(start: T, iter: &fn(f: &fn(U) -> bool) -> bool, f: &fn(&mut T, U)) -> T {
+    let mut result = start;
+    for iter |x| {
+        f(&mut result, x);
+    }
+    result
+}
+
+/**
+ * Reduce an iterator to an accumulated value.
+ *
+ * `fold_ref` is usable in some generic functions where `fold` is too lenient to type-check, but it
+ * forces the iterator to yield borrowed pointers.
+ *
+ * # Example:
+ *
+ * ~~~~
+ * fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
+ *     fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x))
+ * }
+ * ~~~~
+ */
+#[cfg(not(stage0))]
+#[inline]
+pub fn fold_ref<T, U>(start: T, iter: &fn(f: &fn(&U) -> bool) -> bool, f: &fn(&mut T, &U)) -> T {
+    let mut result = start;
+    for iter |x| {
+        f(&mut result, x);
+    }
+    result
+}
+
+/**
+ * Return the sum of the items yielding by an iterator.
+ *
+ * # Example:
+ *
+ * ~~~~
+ * let xs: ~[int] = ~[1, 2, 3, 4];
+ * assert_eq!(do sum |f| { xs.each(f) }, 10);
+ * ~~~~
+ */
+#[cfg(not(stage0))]
+#[inline(always)]
+pub fn sum<T: Zero + Add<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
+    fold_ref(Zero::zero::<T>(), iter, |a, x| *a = a.add(x))
+}
+
+/**
+ * Return the product of the items yielded by an iterator.
+ *
+ * # Example:
+ *
+ * ~~~~
+ * let xs: ~[int] = ~[1, 2, 3, 4];
+ * assert_eq!(do product |f| { xs.each(f) }, 24);
+ * ~~~~
+ */
+#[cfg(not(stage0))]
+#[inline(always)]
+pub fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
+    fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x))
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -254,4 +331,33 @@ mod tests {
         let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
         assert_eq!(min(|f| xs.each(f)).unwrap(), &-5);
     }
+
+    #[test]
+    fn test_fold() {
+        assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10);
+    }
+
+    #[test]
+    fn test_sum() {
+        let xs: ~[int] = ~[1, 2, 3, 4];
+        assert_eq!(do sum |f| { xs.each(f) }, 10);
+    }
+
+    #[test]
+    fn test_empty_sum() {
+        let xs: ~[int] = ~[];
+        assert_eq!(do sum |f| { xs.each(f) }, 0);
+    }
+
+    #[test]
+    fn test_product() {
+        let xs: ~[int] = ~[1, 2, 3, 4];
+        assert_eq!(do product |f| { xs.each(f) }, 24);
+    }
+
+    #[test]
+    fn test_empty_product() {
+        let xs: ~[int] = ~[];
+        assert_eq!(do product |f| { xs.each(f) }, 1);
+    }
 }
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index af30e87bb0c..4a3ec3528f2 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -414,6 +414,12 @@ impl Trigonometric for f32 {
 
     #[inline(always)]
     fn atan2(&self, other: f32) -> f32 { atan2(*self, other) }
+
+    /// Simultaneously computes the sine and cosine of the number
+    #[inline(always)]
+    fn sin_cos(&self) -> (f32, f32) {
+        (self.sin(), self.cos())
+    }
 }
 
 impl Exponential for f32 {
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index 240d84b8403..e370f43a003 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -426,6 +426,12 @@ impl Trigonometric for f64 {
 
     #[inline(always)]
     fn atan2(&self, other: f64) -> f64 { atan2(*self, other) }
+
+    /// Simultaneously computes the sine and cosine of the number
+    #[inline(always)]
+    fn sin_cos(&self) -> (f64, f64) {
+        (self.sin(), self.cos())
+    }
 }
 
 impl Exponential for f64 {
diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs
index 8b3c7b1e79e..681aafaab88 100644
--- a/src/libcore/num/float.rs
+++ b/src/libcore/num/float.rs
@@ -530,6 +530,14 @@ impl Trigonometric for float {
     fn atan2(&self, other: float) -> float {
         (*self as f64).atan2(other as f64) as float
     }
+
+    /// Simultaneously computes the sine and cosine of the number
+    #[inline(always)]
+    fn sin_cos(&self) -> (float, float) {
+        match (*self as f64).sin_cos() {
+            (s, c) => (s as float, c as float)
+        }
+    }
 }
 
 impl Exponential for float {
diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs
index a15a8f1a215..96b302d3174 100644
--- a/src/libcore/num/num.rs
+++ b/src/libcore/num/num.rs
@@ -118,6 +118,7 @@ pub trait Trigonometric {
     fn acos(&self) -> Self;
     fn atan(&self) -> Self;
     fn atan2(&self, other: Self) -> Self;
+    fn sin_cos(&self) -> (Self, Self);
 }
 
 pub trait Exponential {
@@ -395,8 +396,7 @@ pub trait FromStrRadix {
 /// - If code written to use this function doesn't care about it, it's
 ///   probably assuming that `x^0` always equals `1`.
 ///
-pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>(
-    radix: uint, pow: uint) -> T {
+pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>(radix: uint, pow: uint) -> T {
     let _0: T = Zero::zero();
     let _1: T = One::one();
 
@@ -404,7 +404,7 @@ pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>(
     if radix == 0u { return _0; }
     let mut my_pow     = pow;
     let mut total      = _1;
-    let mut multiplier = cast(radix as int);
+    let mut multiplier = cast(radix);
     while (my_pow > 0u) {
         if my_pow % 2u == 1u {
             total *= multiplier;
@@ -421,13 +421,13 @@ pub fn test_num<T:Num + NumCast>(ten: T, two: T) {
     assert_eq!(ten.add(&two),  cast(12));
     assert_eq!(ten.sub(&two),  cast(8));
     assert_eq!(ten.mul(&two),  cast(20));
-    assert_eq!(ten.div(&two), cast(5));
+    assert_eq!(ten.div(&two),  cast(5));
     assert_eq!(ten.rem(&two),  cast(0));
 
     assert_eq!(ten.add(&two),  ten + two);
     assert_eq!(ten.sub(&two),  ten - two);
     assert_eq!(ten.mul(&two),  ten * two);
-    assert_eq!(ten.div(&two), ten / two);
+    assert_eq!(ten.div(&two),  ten / two);
     assert_eq!(ten.rem(&two),  ten % two);
 }
 
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index 9aaa2921fe7..5aee3077e48 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -49,6 +49,7 @@ use num::Zero;
 use old_iter::{BaseIter, MutableIter, ExtendedIter};
 use old_iter;
 use str::StrSlice;
+use clone::DeepClone;
 
 #[cfg(test)] use str;
 
@@ -59,6 +60,15 @@ pub enum Option<T> {
     Some(T),
 }
 
+impl<T: DeepClone> DeepClone for Option<T> {
+    fn deep_clone(&self) -> Option<T> {
+        match *self {
+            Some(ref x) => Some(x.deep_clone()),
+            None => None
+        }
+    }
+}
+
 impl<T:Ord> Ord for Option<T> {
     fn lt(&self, other: &Option<T>) -> bool {
         match (self, other) {
diff --git a/src/libcore/os.rs b/src/libcore/os.rs
index 61c80c89894..72e62c80392 100644
--- a/src/libcore/os.rs
+++ b/src/libcore/os.rs
@@ -291,6 +291,33 @@ pub fn setenv(n: &str, v: &str) {
     }
 }
 
+/// Remove a variable from the environment entirely
+pub fn unsetenv(n: &str) {
+    #[cfg(unix)]
+    fn _unsetenv(n: &str) {
+        unsafe {
+            do with_env_lock {
+                do str::as_c_str(n) |nbuf| {
+                    libc::funcs::posix01::unistd::unsetenv(nbuf);
+                }
+            }
+        }
+    }
+    #[cfg(windows)]
+    fn _unsetenv(n: &str) {
+        unsafe {
+            do with_env_lock {
+                use os::win32::as_utf16_p;
+                do as_utf16_p(n) |nbuf| {
+                    libc::SetEnvironmentVariableW(nbuf, ptr::null());
+                }
+            }
+        }
+    }
+
+    _unsetenv(n);
+}
+
 pub fn fdopen(fd: c_int) -> *FILE {
     unsafe {
         return do as_c_charp("r") |modebuf| {
@@ -1414,7 +1441,7 @@ mod tests {
     use option::Some;
     use option;
     use os::{as_c_charp, env, getcwd, getenv, make_absolute, real_args};
-    use os::{remove_file, setenv};
+    use os::{remove_file, setenv, unsetenv};
     use os;
     use path::Path;
     use rand::RngUtil;
@@ -1451,6 +1478,14 @@ mod tests {
     }
 
     #[test]
+    fn test_unsetenv() {
+        let n = make_rand_name();
+        setenv(n, ~"VALUE");
+        unsetenv(n);
+        assert!(getenv(n) == option::None);
+    }
+
+    #[test]
     #[ignore(cfg(windows))]
     #[ignore]
     fn test_setenv_overwrite() {
diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs
index 22172db9302..4ed648161fc 100644
--- a/src/libcore/prelude.rs
+++ b/src/libcore/prelude.rs
@@ -27,7 +27,7 @@ pub use io::{print, println};
 
 /* Reexported types and traits */
 
-pub use clone::Clone;
+pub use clone::{Clone, DeepClone};
 pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
 pub use container::{Container, Mutable, Map, Set};
 pub use hash::Hash;
diff --git a/src/libcore/rt/stack.rs b/src/libcore/rt/stack.rs
index 019540ce76b..cab9c3390b2 100644
--- a/src/libcore/rt/stack.rs
+++ b/src/libcore/rt/stack.rs
@@ -46,9 +46,7 @@ pub impl StackSegment {
 
     /// Point one word beyond the high end of the allocated stack
     fn end(&self) -> *uint {
-        unsafe {
-            vec::raw::to_ptr(self.buf).offset(self.buf.len()) as *uint
-        }
+        vec::raw::to_ptr(self.buf).offset(self.buf.len()) as *uint
     }
 }
 
diff --git a/src/libcore/rt/uv/mod.rs b/src/libcore/rt/uv/mod.rs
index 93cafb83588..99a5252c88a 100644
--- a/src/libcore/rt/uv/mod.rs
+++ b/src/libcore/rt/uv/mod.rs
@@ -309,7 +309,7 @@ pub type Buf = uvll::uv_buf_t;
 
 /// Borrow a slice to a Buf
 pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
-    let data = unsafe { vec::raw::to_ptr(v) };
+    let data = vec::raw::to_ptr(v);
     unsafe { uvll::buf_init(data, v.len()) }
 }
 
diff --git a/src/libcore/unstable/intrinsics.rs b/src/libcore/unstable/intrinsics.rs
index b8c0c4e4a92..1636abedf7a 100644
--- a/src/libcore/unstable/intrinsics.rs
+++ b/src/libcore/unstable/intrinsics.rs
@@ -8,62 +8,119 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-/*!
-An attempt to move all intrinsic declarations to a single place,
-as mentioned in #3369
-The intrinsics are defined in librustc/middle/trans/foreign.rs.
+/*! rustc compiler intrinsics.
+
+The corresponding definitions are in librustc/middle/trans/foreign.rs.
+
+# Atomics
+
+The atomic intrinsics provide common atomic operations on machine
+words, with multiple possible memory orderings. They obey the same
+semantics as C++0x. See the LLVM documentation on [[atomics]].
+
+[atomics]: http://llvm.org/docs/Atomics.html
+
+A quick refresher on memory ordering:
+
+* Acquire - a barrier for aquiring a lock. Subsequent reads and writes
+  take place after the barrier.
+* Release - a barrier for releasing a lock. Preceding reads and writes
+  take place before the barrier.
+* Sequentially consistent - sequentially consistent operations are
+  guaranteed to happen in order. This is the standard mode for working
+  with atomic types and is equivalent to Java's `volatile`.
+
 */
 
 #[abi = "rust-intrinsic"]
 pub extern "rust-intrinsic" {
+
+    /// Atomic compare and exchange, sequentially consistent.
     pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int;
+    /// Atomic compare and exchange, acquire ordering.
     pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int;
+    /// Atomic compare and exchange, release ordering.
     pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int;
 
+    /// Atomic load, sequentially consistent.
     #[cfg(not(stage0))]
     pub fn atomic_load(src: &int) -> int;
+    /// Atomic load, acquire ordering.
     #[cfg(not(stage0))]
     pub fn atomic_load_acq(src: &int) -> int;
 
+    /// Atomic store, sequentially consistent.
     #[cfg(not(stage0))]
     pub fn atomic_store(dst: &mut int, val: int);
+    /// Atomic store, release ordering.
     #[cfg(not(stage0))]
     pub fn atomic_store_rel(dst: &mut int, val: int);
 
+    /// Atomic exchange, sequentially consistent.
     pub fn atomic_xchg(dst: &mut int, src: int) -> int;
+    /// Atomic exchange, acquire ordering.
     pub fn atomic_xchg_acq(dst: &mut int, src: int) -> int;
+    /// Atomic exchange, release ordering.
     pub fn atomic_xchg_rel(dst: &mut int, src: int) -> int;
 
+    /// Atomic addition, sequentially consistent.
     pub fn atomic_xadd(dst: &mut int, src: int) -> int;
+    /// Atomic addition, acquire ordering.
     pub fn atomic_xadd_acq(dst: &mut int, src: int) -> int;
+    /// Atomic addition, release ordering.
     pub fn atomic_xadd_rel(dst: &mut int, src: int) -> int;
 
+    /// Atomic subtraction, sequentially consistent.
     pub fn atomic_xsub(dst: &mut int, src: int) -> int;
+    /// Atomic subtraction, acquire ordering.
     pub fn atomic_xsub_acq(dst: &mut int, src: int) -> int;
+    /// Atomic subtraction, release ordering.
     pub fn atomic_xsub_rel(dst: &mut int, src: int) -> int;
 
+    /// The size of a type in bytes.
+    ///
+    /// This is the exact number of bytes in memory taken up by a
+    /// value of the given type. In other words, a memset of this size
+    /// would *exactly* overwrite a value. When laid out in vectors
+    /// and structures there may be additional padding between
+    /// elements.
     pub fn size_of<T>() -> uint;
 
+    /// Move a value to a memory location containing a value.
+    ///
+    /// Drop glue is run on the destination, which must contain a
+    /// valid Rust value.
     pub fn move_val<T>(dst: &mut T, src: T);
+
+    /// Move a value to an uninitialized memory location.
+    ///
+    /// Drop glue is not run on the destination.
     pub fn move_val_init<T>(dst: &mut T, src: T);
 
     pub fn min_align_of<T>() -> uint;
     pub fn pref_align_of<T>() -> uint;
 
+    /// Get a static pointer to a type descriptor.
     pub fn get_tydesc<T>() -> *();
 
-    /// init is unsafe because it returns a zeroed-out datum,
+    /// Create a value initialized to zero.
+    ///
+    /// `init` is unsafe because it returns a zeroed-out datum,
     /// which is unsafe unless T is POD. We don't have a POD
-    /// kind yet. (See #4074)
+    /// kind yet. (See #4074).
     pub unsafe fn init<T>() -> T;
 
+    /// Create an uninitialized value.
     #[cfg(not(stage0))]
     pub unsafe fn uninit<T>() -> T;
 
-    /// forget is unsafe because the caller is responsible for
-    /// ensuring the argument is deallocated already
+    /// Move a value out of scope without running drop glue.
+    ///
+    /// `forget` is unsafe because the caller is responsible for
+    /// ensuring the argument is deallocated already.
     pub unsafe fn forget<T>(_: T) -> ();
 
+    /// Returns `true` if a type requires drop glue.
     pub fn needs_drop<T>() -> bool;
 
     // XXX: intrinsic uses legacy modes and has reference to TyDesc
@@ -72,9 +129,12 @@ pub extern "rust-intrinsic" {
     // XXX: intrinsic uses legacy modes
     //fn frame_address(f: &once fn(*u8));
 
+    /// Get the address of the `__morestack` stack growth function.
     pub fn morestack_addr() -> *();
 
+    /// Equivalent to the `llvm.memmove.p0i8.0i8.i32` intrinsic.
     pub fn memmove32(dst: *mut u8, src: *u8, size: u32);
+    /// Equivalent to the `llvm.memmove.p0i8.0i8.i64` intrinsic.
     pub fn memmove64(dst: *mut u8, src: *u8, size: u64);
 
     pub fn sqrtf32(x: f32) -> f32;
diff --git a/src/libcore/util.rs b/src/libcore/util.rs
index d270fb23aaa..e5067fb90bc 100644
--- a/src/libcore/util.rs
+++ b/src/libcore/util.rs
@@ -138,8 +138,8 @@ pub enum Void { }
 
 pub impl Void {
     /// A utility function for ignoring this uninhabited type
-    fn uninhabited(&self) -> ! {
-        match *self {
+    fn uninhabited(self) -> ! {
+        match self {
             // Nothing to match on
         }
     }
@@ -177,7 +177,8 @@ pub fn unreachable() -> ! {
 #[cfg(test)]
 mod tests {
     use option::{None, Some};
-    use util::{NonCopyable, id, replace, swap};
+    use util::{Void, NonCopyable, id, replace, swap};
+    use either::{Either, Left, Right};
 
     #[test]
     pub fn identity_crisis() {
@@ -202,4 +203,12 @@ mod tests {
         assert!(x.is_none());
         assert!(y.is_some());
     }
+    #[test]
+    pub fn test_uninhabited() {
+        let could_only_be_coin : Either <Void, ()> = Right (());
+        match could_only_be_coin {
+            Right (coin) => coin,
+            Left (is_void) => is_void.uninhabited ()
+        }
+    }
 }
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 0fb697b686f..4c6e0791ba2 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -1445,6 +1445,46 @@ pub fn reverse<T>(v: &mut [T]) {
     }
 }
 
+/**
+ * Reverse part of a vector in place.
+ *
+ * Reverse the elements in the vector between `start` and `end - 1`.
+ *
+ * If either start or end do not represent valid positions in the vector, the
+ * vector is returned unchanged.
+ *
+ * # Arguments
+ *
+ * * `v` - The mutable vector to be modified
+ *
+ * * `start` - Index of the first element of the slice
+ *
+ * * `end` - Index one past the final element to be reversed.
+ *
+ * # Example
+ *
+ * Assume a mutable vector `v` contains `[1,2,3,4,5]`. After the call:
+ *
+ * ~~~
+ *
+ * reverse_part(v, 1, 4);
+ *
+ * ~~~
+ *
+ * `v` now contains `[1,4,3,2,5]`.
+ */
+pub fn reverse_part<T>(v: &mut [T], start: uint, end : uint) {
+    let sz = v.len();
+    if start >= sz || end > sz { return; }
+    let mut i = start;
+    let mut j = end - 1;
+    while i < j {
+        vec::swap(v, i, j);
+        i += 1;
+        j -= 1;
+    }
+}
+
 /// Returns a vector with the order of elements reversed
 pub fn reversed<T:Copy>(v: &const [T]) -> ~[T] {
     let mut rs: ~[T] = ~[];
@@ -1739,29 +1779,49 @@ pub fn each2_mut<U, T>(v1: &mut [U], v2: &mut [T], f: &fn(u: &mut U, t: &mut T)
  *
  * The total number of permutations produced is `len(v)!`.  If `v` contains
  * repeated elements, then some permutations are repeated.
+ *
+ * See [Algorithms to generate
+ * permutations](http://en.wikipedia.org/wiki/Permutation).
+ *
+ *  # Arguments
+ *
+ *  * `values` - A vector of values from which the permutations are
+ *  chosen
+ *
+ *  * `fun` - The function to iterate over the combinations
  */
-#[cfg(not(stage0))]
-pub fn each_permutation<T:Copy>(v: &[T], put: &fn(ts: &[T]) -> bool) -> bool {
-    let ln = len(v);
-    if ln <= 1 {
-        put(v);
-    } else {
-        // This does not seem like the most efficient implementation.  You
-        // could make far fewer copies if you put your mind to it.
-        let mut i = 0u;
-        while i < ln {
-            let elt = v[i];
-            let mut rest = slice(v, 0u, i).to_vec();
-            rest.push_all(const_slice(v, i+1u, ln));
-            for each_permutation(rest) |permutation| {
-                if !put(append(~[elt], permutation)) {
-                    return false;
-                }
-            }
-            i += 1u;
+pub fn each_permutation<T:Copy>(values: &[T], fun: &fn(perm : &[T]) -> bool) -> bool {
+    let length = values.len();
+    let mut permutation = vec::from_fn(length, |i| values[i]);
+    if length <= 1 {
+        fun(permutation);
+        return true;
+    }
+    let mut indices = vec::from_fn(length, |i| i);
+    loop {
+        if !fun(permutation) { return true; }
+        // find largest k such that indices[k] < indices[k+1]
+        // if no such k exists, all permutations have been generated
+        let mut k = length - 2;
+        while k > 0 && indices[k] >= indices[k+1] {
+            k -= 1;
+        }
+        if k == 0 && indices[0] > indices[1] { return true; }
+        // find largest l such that indices[k] < indices[l]
+        // k+1 is guaranteed to be such
+        let mut l = length - 1;
+        while indices[k] >= indices[l] {
+            l -= 1;
+        }
+        // swap indices[k] and indices[l]; sort indices[k+1..]
+        // (they're just reversed)
+        vec::swap(indices, k, l);
+        reverse_part(indices, k+1, length);
+        // fixup permutation based on indices
+        for uint::range(k, length) |i| {
+            permutation[i] = values[indices[i]];
         }
     }
-    return true;
 }
 
 /**
@@ -2546,23 +2606,29 @@ pub mod raw {
      * would also make any pointers to it invalid.
      */
     #[inline(always)]
-    pub unsafe fn to_ptr<T>(v: &[T]) -> *T {
-        let repr: **SliceRepr = transmute(&v);
-        transmute(&((**repr).data))
+    pub fn to_ptr<T>(v: &[T]) -> *T {
+        unsafe {
+            let repr: **SliceRepr = transmute(&v);
+            transmute(&((**repr).data))
+        }
     }
 
     /** see `to_ptr()` */
     #[inline(always)]
-    pub unsafe fn to_const_ptr<T>(v: &const [T]) -> *const T {
-        let repr: **SliceRepr = transmute(&v);
-        transmute(&((**repr).data))
+    pub fn to_const_ptr<T>(v: &const [T]) -> *const T {
+        unsafe {
+            let repr: **SliceRepr = transmute(&v);
+            transmute(&((**repr).data))
+        }
     }
 
     /** see `to_ptr()` */
     #[inline(always)]
-    pub unsafe fn to_mut_ptr<T>(v: &mut [T]) -> *mut T {
-        let repr: **SliceRepr = transmute(&v);
-        transmute(&((**repr).data))
+    pub fn to_mut_ptr<T>(v: &mut [T]) -> *mut T {
+        unsafe {
+            let repr: **SliceRepr = transmute(&v);
+            transmute(&((**repr).data))
+        }
     }
 
     /**
@@ -4725,6 +4791,53 @@ mod tests {
     }
 
     #[test]
+    fn test_reverse_part() {
+        let mut values = [1,2,3,4,5];
+        reverse_part(values,1,4);
+        assert_eq!(values, [1,4,3,2,5]);
+    }
+
+    #[test]
+    fn test_permutations0() {
+        let values = [];
+        let mut v : ~[~[int]] = ~[];
+        for each_permutation(values) |p| {
+            v.push(p.to_owned());
+        }
+        assert_eq!(v, ~[~[]]);
+    }
+
+    #[test]
+    fn test_permutations1() {
+        let values = [1];
+        let mut v : ~[~[int]] = ~[];
+        for each_permutation(values) |p| {
+            v.push(p.to_owned());
+        }
+        assert_eq!(v, ~[~[1]]);
+    }
+
+    #[test]
+    fn test_permutations2() {
+        let values = [1,2];
+        let mut v : ~[~[int]] = ~[];
+        for each_permutation(values) |p| {
+            v.push(p.to_owned());
+        }
+        assert_eq!(v, ~[~[1,2],~[2,1]]);
+    }
+
+    #[test]
+    fn test_permutations3() {
+        let values = [1,2,3];
+        let mut v : ~[~[int]] = ~[];
+        for each_permutation(values) |p| {
+            v.push(p.to_owned());
+        }
+        assert_eq!(v, ~[~[1,2,3],~[1,3,2],~[2,1,3],~[2,3,1],~[3,1,2],~[3,2,1]]);
+    }
+
+    #[test]
     fn test_each_val() {
         use old_iter::CopyableNonstrictIter;
         let mut i = 0;
diff --git a/src/librustc/README.txt b/src/librustc/README.txt
index 487a7927d27..6d4a8157f11 100644
--- a/src/librustc/README.txt
+++ b/src/librustc/README.txt
@@ -35,19 +35,19 @@ ASTs -- are in a separate crate called "syntax", whose files are in
 ./../libsyntax, where . is the current directory (that is, the parent
 directory of front/, middle/, back/, and so on).
 
-The entry-point for the compiler is main() in driver/rustc.rs, and
+The entry-point for the compiler is main() in rustc.rc, and
 this file sequences the various parts together.
 
 
 The 3 central data structures:
 ------------------------------
 
-#1: ../libsyntax/ast.rs defines the AST. The AST is treated as immutable
+#1: ./../libsyntax/ast.rs defines the AST. The AST is treated as immutable
     after parsing, but it depends on mutable context data structures
     (mainly hash maps) to give it meaning.
 
       - Many -- though not all -- nodes within this data structure are
-        wrapped in the type spanned<T>, meaning that the front-end has
+        wrapped in the type `spanned<T>`, meaning that the front-end has
         marked the input coordinates of that node. The member .node is
         the data itself, the member .span is the input location (file,
         line, column; both low and high).
@@ -78,7 +78,7 @@ Control and information flow within the compiler:
 - main() in rustc.rc assumes control on startup. Options are
   parsed, platform is detected, etc.
 
-- libsyntax/parse/parser.rs parses the input files and produces an AST
+- ./../libsyntax/parse/parser.rs parses the input files and produces an AST
   that represents the input crate.
 
 - Multiple middle-end passes (middle/resolve.rs, middle/typeck.rs)
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index 0e2739e40a9..92d3a451559 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -171,7 +171,6 @@ pub mod write {
     use back::link::{output_type_assembly, output_type_bitcode};
     use back::link::{output_type_exe, output_type_llvm_assembly};
     use back::link::{output_type_object};
-    use back::link::output_type;
     use driver::session::Session;
     use driver::session;
     use lib::llvm::llvm;
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 0e37653e5c4..99ffa8cc94a 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -22,6 +22,7 @@ use middle;
 use util::common::time;
 use util::ppaux;
 
+use core::hashmap::HashMap;
 use core::int;
 use core::io;
 use core::os;
@@ -200,9 +201,6 @@ pub fn compile_rest(sess: Session,
     crate = time(time_passes, ~"core injection", ||
         front::core_inject::maybe_inject_libcore_ref(sess, crate));
 
-    time(time_passes, ~"building lint settings table", ||
-        lint::build_settings_crate(sess, crate));
-
     let ast_map = time(time_passes, ~"ast indexing", ||
             syntax::ast_map::map_crate(sess.diagnostic(), crate));
 
@@ -709,7 +707,6 @@ pub fn build_session_(sopts: @session::options,
         &sopts.maybe_sysroot,
         sopts.target_triple,
         /*bad*/copy sopts.addl_lib_search_paths);
-    let lint_settings = lint::mk_lint_settings();
     @Session_ {
         targ_cfg: target_cfg,
         opts: sopts,
@@ -723,7 +720,7 @@ pub fn build_session_(sopts: @session::options,
         filesearch: filesearch,
         building_library: @mut false,
         working_dir: os::getcwd(),
-        lint_settings: lint_settings
+        lints: @mut HashMap::new(),
     }
 }
 
diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs
index 16eec0b10de..6fba5ec8d3a 100644
--- a/src/librustc/driver/session.rs
+++ b/src/librustc/driver/session.rs
@@ -26,6 +26,8 @@ use syntax::{ast, codemap};
 use syntax::abi;
 use syntax;
 
+use core::hashmap::HashMap;
+
 #[deriving(Eq)]
 pub enum os { os_win32, os_macos, os_linux, os_android, os_freebsd, }
 
@@ -170,7 +172,7 @@ pub struct Session_ {
     filesearch: @filesearch::FileSearch,
     building_library: @mut bool,
     working_dir: Path,
-    lint_settings: lint::LintSettings
+    lints: @mut HashMap<ast::node_id, ~[(lint::lint, codemap::span, ~str)]>,
 }
 
 pub type Session = @Session_;
@@ -221,24 +223,12 @@ pub impl Session_ {
     fn unimpl(@self, msg: &str) -> ! {
         self.span_diagnostic.handler().unimpl(msg)
     }
-    fn span_lint_level(@self, level: lint::level, sp: span, msg: &str) {
-        match level {
-          lint::allow => { },
-          lint::warn => self.span_warn(sp, msg),
-          lint::deny | lint::forbid => {
-            self.span_err(sp, msg);
-          }
+    fn add_lint(@self, lint: lint::lint, id: ast::node_id, sp: span, msg: ~str) {
+        match self.lints.find_mut(&id) {
+            Some(arr) => { arr.push((lint, sp, msg)); return; }
+            None => {}
         }
-    }
-    fn span_lint(@self, lint_mode: lint::lint,
-                 expr_id: ast::node_id,
-                 item_id: ast::node_id,
-                 span: span,
-                 msg: &str) {
-        let level = lint::get_lint_settings_level(
-            self.lint_settings, lint_mode, expr_id, item_id);
-        let msg = fmt!("%s [-W %s]", msg, lint::get_lint_name(lint_mode));
-        self.span_lint_level(level, span, msg);
+        self.lints.insert(id, ~[(lint, sp, msg)]);
     }
     fn next_node_id(@self) -> ast::node_id {
         return syntax::parse::next_node_id(self.parse_sess);
diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs
index ad40faebe06..d06bf1480c9 100644
--- a/src/librustc/lib/llvm.rs
+++ b/src/librustc/lib/llvm.rs
@@ -1566,6 +1566,7 @@ pub mod llvm {
         /* Atomic Operations */
         pub unsafe fn LLVMBuildAtomicLoad(B: BuilderRef,
                                           PointerVal: ValueRef,
+                                          Name: *c_char,
                                           Order: AtomicOrdering)
                                        -> ValueRef;
 
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index e6b8432854d..5a0820202a9 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -234,14 +234,13 @@ pub fn get_field_type(tcx: ty::ctxt, class_id: ast::def_id,
     }
 }
 
-// Given a def_id for an impl or class, return the traits it implements,
-// or the empty vector if it's not for an impl or for a class that implements
-// traits
-pub fn get_impl_traits(tcx: ty::ctxt,
-                       def: ast::def_id) -> ~[@ty::TraitRef] {
+// Given a def_id for an impl, return the trait it implements,
+// if there is one.
+pub fn get_impl_trait(tcx: ty::ctxt,
+                      def: ast::def_id) -> Option<@ty::TraitRef> {
     let cstore = tcx.cstore;
     let cdata = cstore::get_crate_data(cstore, def.crate);
-    decoder::get_impl_traits(cdata, def.node, tcx)
+    decoder::get_impl_trait(cdata, def.node, tcx)
 }
 
 pub fn get_impl_method(cstore: @mut cstore::CStore,
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 2592875cd57..43073728e83 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -415,19 +415,20 @@ pub fn get_type_param_count(data: @~[u8], id: ast::node_id) -> uint {
     item_ty_param_count(lookup_item(id, data))
 }
 
-pub fn get_impl_traits(cdata: cmd,
+pub fn get_impl_trait(cdata: cmd,
                        id: ast::node_id,
-                       tcx: ty::ctxt) -> ~[@ty::TraitRef]
+                       tcx: ty::ctxt) -> Option<@ty::TraitRef>
 {
     let item_doc = lookup_item(id, cdata.data);
-    let mut results = ~[];
+    let mut result = None;
     for reader::tagged_docs(item_doc, tag_item_trait_ref) |tp| {
         let trait_ref =
             @parse_trait_ref_data(tp.data, cdata.cnum, tp.start, tcx,
                                   |_, did| translate_def_id(cdata, did));
-        results.push(trait_ref);
+        result = Some(trait_ref);
+        break;
     };
-    results
+    result
 }
 
 pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id,
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index 151ccad88ea..55a0755f5e3 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -470,12 +470,14 @@ fn parse_closure_ty(st: @mut PState, conv: conv_did) -> ty::ClosureTy {
     let purity = parse_purity(next(st));
     let onceness = parse_onceness(next(st));
     let region = parse_region(st);
+    let bounds = parse_bounds(st, conv);
     let sig = parse_sig(st, conv);
     ty::ClosureTy {
         purity: purity,
         sigil: sigil,
         onceness: onceness,
         region: region,
+        bounds: bounds.builtin_bounds,
         sig: sig
     }
 }
@@ -540,10 +542,10 @@ pub fn parse_type_param_def_data(data: @~[u8], start: uint,
 
 fn parse_type_param_def(st: @mut PState, conv: conv_did) -> ty::TypeParameterDef {
     ty::TypeParameterDef {def_id: parse_def(st, NominalType, conv),
-                          bounds: parse_bounds(st, conv)}
+                          bounds: @parse_bounds(st, conv)}
 }
 
-fn parse_bounds(st: @mut PState, conv: conv_did) -> @ty::ParamBounds {
+fn parse_bounds(st: @mut PState, conv: conv_did) -> ty::ParamBounds {
     let mut param_bounds = ty::ParamBounds {
         builtin_bounds: ty::EmptyBuiltinBounds(),
         trait_bounds: ~[]
@@ -566,7 +568,7 @@ fn parse_bounds(st: @mut PState, conv: conv_did) -> @ty::ParamBounds {
                 param_bounds.trait_bounds.push(@parse_trait_ref(st, conv));
             }
             '.' => {
-                return @param_bounds;
+                return param_bounds;
             }
             _ => {
                 fail!("parse_bounds: bad bounds")
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index 2cb95e1a2fc..5f799f49946 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -380,6 +380,9 @@ fn enc_closure_ty(w: @io::Writer, cx: @ctxt, ft: &ty::ClosureTy) {
     enc_purity(w, ft.purity);
     enc_onceness(w, ft.onceness);
     enc_region(w, cx, ft.region);
+    let bounds = ty::ParamBounds {builtin_bounds: ft.bounds,
+                                  trait_bounds: ~[]};
+    enc_bounds(w, cx, &bounds);
     enc_fn_sig(w, cx, &ft.sig);
 }
 
@@ -392,7 +395,7 @@ fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) {
     enc_ty(w, cx, fsig.output);
 }
 
-fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @ty::ParamBounds) {
+fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: &ty::ParamBounds) {
     for bs.builtin_bounds.each |bound| {
         match bound {
             ty::BoundOwned => w.write_char('S'),
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 2996c4c8476..209a14942e9 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -1108,7 +1108,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
                 dcx.tcx.adjustments.insert(id, adj);
             } else if tag == (c::tag_table_capture_map as uint) {
                 let cvars =
-                    at_vec::from_owned(
+                    at_vec::to_managed_consume(
                         val_dsr.read_to_vec(
                             |val_dsr| val_dsr.read_capture_var(xcx)));
                 dcx.maps.capture_map.insert(id, cvars);
diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs
index 330d60a59d3..e377bebcc26 100644
--- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs
+++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs
@@ -93,7 +93,7 @@ impl GuaranteeLifetimeContext {
                 let omit_root = (
                     ptr_mutbl == m_imm &&
                     self.bccx.is_subregion_of(self.loan_region, base_scope) &&
-                    base.mutbl.is_immutable() &&
+                    self.is_rvalue_or_immutable(base) &&
                     !self.is_moved(base)
                 );
 
@@ -168,6 +168,19 @@ impl GuaranteeLifetimeContext {
         }
     }
 
+    fn is_rvalue_or_immutable(&self,
+                              cmt: mc::cmt) -> bool {
+        //! We can omit the root on an `@T` value if the location
+        //! that holds the box is either (1) an rvalue, in which case
+        //! it is in a non-user-accessible temporary, or (2) an immutable
+        //! lvalue.
+
+        cmt.mutbl.is_immutable() || match cmt.guarantor().cat {
+            mc::cat_rvalue => true,
+            _ => false
+        }
+    }
+
     fn check_root(&self,
                   cmt_deref: mc::cmt,
                   cmt_base: mc::cmt,
diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs
index 41e29132155..872ad83b739 100644
--- a/src/librustc/middle/freevars.rs
+++ b/src/librustc/middle/freevars.rs
@@ -20,8 +20,7 @@ use syntax::{ast, ast_util, visit};
 
 // A vector of defs representing the free variables referred to in a function.
 // (The def_upvar will already have been stripped).
-#[auto_encode]
-#[auto_decode]
+#[deriving(Encodable, Decodable)]
 pub struct freevar_entry {
     def: ast::def, //< The variable being accessed free.
     span: span     //< First span where it is accessed (there can be multiple)
diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs
index 7ea0840880c..591b196bd6f 100644
--- a/src/librustc/middle/lint.rs
+++ b/src/librustc/middle/lint.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use driver::session::Session;
 use driver::session;
 use middle::ty;
 use middle::pat_util;
@@ -19,7 +18,7 @@ use std::smallintmap::SmallIntMap;
 use syntax::attr;
 use syntax::codemap::span;
 use syntax::codemap;
-use syntax::{ast, visit};
+use syntax::{ast, visit, ast_util};
 
 /**
  * A 'lint' check is a kind of miscellaneous constraint that a user _might_
@@ -28,18 +27,34 @@ use syntax::{ast, visit};
  * other phases of the compiler, which are generally required to hold in order
  * to compile the program at all.
  *
- * We also build up a table containing information about lint settings, in
- * order to allow other passes to take advantage of the lint attribute
- * infrastructure. To save space, the table is keyed by the id of /items/, not
- * of every expression. When an item has the default settings, the entry will
- * be omitted. If we start allowing lint attributes on expressions, we will
- * start having entries for expressions that do not share their enclosing
- * items settings.
+ * The lint checking is all consolidated into one pass which runs just before
+ * translation to LLVM bytecode. Throughout compilation, lint warnings can be
+ * added via the `add_lint` method on the Session structure. This requires a
+ * span and an id of the node that the lint is being added to. The lint isn't
+ * actually emitted at that time because it is unknown what the actual lint
+ * level at that location is.
  *
- * This module then, exports two passes: one that populates the lint
- * settings table in the session and is run early in the compile process, and
- * one that does a variety of lint checks, and is run late in the compile
- * process.
+ * To actually emit lint warnings/errors, a separate pass is used just before
+ * translation. A context keeps track of the current state of all lint levels.
+ * Upon entering a node of the ast which can modify the lint settings, the
+ * previous lint state is pushed onto a stack and the ast is then recursed upon.
+ * As the ast is traversed, this keeps track of the current lint level for all
+ * lint attributes.
+ *
+ * At each node of the ast which can modify lint attributes, all known lint
+ * passes are also applied.  Each lint pass is a visit::vt<()> structure. These
+ * visitors are constructed via the lint_*() functions below. There are also
+ * some lint checks which operate directly on ast nodes (such as @ast::item),
+ * and those are organized as check_item_*(). Each visitor added to the lint
+ * context is modified to stop once it reaches a node which could alter the lint
+ * levels. This means that everything is looked at once and only once by every
+ * lint pass.
+ *
+ * With this all in place, to add a new lint warning, all you need to do is to
+ * either invoke `add_lint` on the session at the appropriate time, or write a
+ * lint pass in this module which is just an ast visitor. The context used when
+ * traversing the ast has a `span_lint` method which only needs the span of the
+ * item that's being warned about.
  */
 
 #[deriving(Eq)]
@@ -86,7 +101,20 @@ struct LintSpec {
     default: level
 }
 
-pub type LintDict = @HashMap<~str, LintSpec>;
+pub type LintDict = HashMap<~str, LintSpec>;
+
+enum AttributedNode<'self> {
+    Item(@ast::item),
+    Method(&'self ast::method),
+    Crate(@ast::crate),
+}
+
+#[deriving(Eq)]
+enum LintSource {
+    Node(span),
+    Default,
+    CommandLine
+}
 
 static lint_table: &'static [(&'static str, LintSpec)] = &[
     ("ctypes",
@@ -225,82 +253,90 @@ pub fn get_lint_dict() -> LintDict {
     for lint_table.each|&(k, v)| {
         map.insert(k.to_str(), v);
     }
-    return @map;
-}
-
-pub fn get_lint_name(lint_mode: lint) -> ~str {
-    for lint_table.each |&(name, spec)| {
-        if spec.lint == lint_mode {
-            return name.to_str();
-        }
-    }
-    fail!();
-}
-// This is a highly not-optimal set of data structure decisions.
-type LintModes = @mut SmallIntMap<level>;
-type LintModeMap = @mut HashMap<ast::node_id, LintModes>;
-
-// settings_map maps node ids of items with non-default lint settings
-// to their settings; default_settings contains the settings for everything
-// not in the map.
-pub struct LintSettings {
-    default_settings: LintModes,
-    settings_map: LintModeMap
-}
-
-pub fn mk_lint_settings() -> LintSettings {
-    LintSettings {
-        default_settings: @mut SmallIntMap::new(),
-        settings_map: @mut HashMap::new()
-    }
-}
-
-pub fn get_lint_level(modes: LintModes, lint: lint) -> level {
-    match modes.find(&(lint as uint)) {
-      Some(&c) => c,
-      None => allow
-    }
-}
-
-pub fn get_lint_settings_level(settings: LintSettings,
-                               lint_mode: lint,
-                               _expr_id: ast::node_id,
-                               item_id: ast::node_id)
-                            -> level {
-    match settings.settings_map.find(&item_id) {
-      Some(&modes) => get_lint_level(modes, lint_mode),
-      None => get_lint_level(settings.default_settings, lint_mode)
-    }
-}
-
-// This is kind of unfortunate. It should be somewhere else, or we should use
-// a persistent data structure...
-fn clone_lint_modes(modes: LintModes) -> LintModes {
-    @mut (copy *modes)
+    return map;
 }
 
 struct Context {
-    dict: LintDict,
-    curr: LintModes,
-    is_default: bool,
-    sess: Session
+    // All known lint modes (string versions)
+    dict: @LintDict,
+    // Current levels of each lint warning
+    curr: SmallIntMap<(level, LintSource)>,
+    // context we're checking in (used to access fields like sess)
+    tcx: ty::ctxt,
+    // When recursing into an attributed node of the ast which modifies lint
+    // levels, this stack keeps track of the previous lint levels of whatever
+    // was modified.
+    lint_stack: ~[(lint, level, LintSource)],
+    // Each of these visitors represents a lint pass. A number of the lint
+    // attributes are registered by adding a visitor to iterate over the ast.
+    // Others operate directly on @ast::item structures (or similar). Finally,
+    // others still are added to the Session object via `add_lint`, and these
+    // are all passed with the lint_session visitor.
+    visitors: ~[visit::vt<()>],
 }
 
-pub impl Context {
+impl Context {
     fn get_level(&self, lint: lint) -> level {
-        get_lint_level(self.curr, lint)
+        match self.curr.find(&(lint as uint)) {
+          Some(&(lvl, _)) => lvl,
+          None => allow
+        }
+    }
+
+    fn get_source(&self, lint: lint) -> LintSource {
+        match self.curr.find(&(lint as uint)) {
+          Some(&(_, src)) => src,
+          None => Default
+        }
     }
 
-    fn set_level(&self, lint: lint, level: level) {
+    fn set_level(&mut self, lint: lint, level: level, src: LintSource) {
         if level == allow {
             self.curr.remove(&(lint as uint));
         } else {
-            self.curr.insert(lint as uint, level);
+            self.curr.insert(lint as uint, (level, src));
+        }
+    }
+
+    fn lint_to_str(&self, lint: lint) -> ~str {
+        for self.dict.each |k, v| {
+            if v.lint == lint {
+                return copy *k;
+            }
         }
+        fail!("unregistered lint %?", lint);
     }
 
-    fn span_lint(&self, level: level, span: span, msg: ~str) {
-        self.sess.span_lint_level(level, span, msg);
+    fn span_lint(&self, lint: lint, span: span, msg: &str) {
+        let (level, src) = match self.curr.find(&(lint as uint)) {
+            Some(&pair) => pair,
+            None => { return; }
+        };
+        if level == allow { return; }
+
+        let mut note = None;
+        let msg = match src {
+            Default | CommandLine => {
+                fmt!("%s [-%c %s%s]", msg, match level {
+                        warn => 'W', deny => 'D', forbid => 'F',
+                        allow => fail!()
+                    }, str::replace(self.lint_to_str(lint), "_", "-"),
+                    if src == Default { " (default)" } else { "" })
+            },
+            Node(src) => {
+                note = Some(src);
+                msg.to_str()
+            }
+        };
+        match level {
+            warn =>          { self.tcx.sess.span_warn(span, msg); }
+            deny | forbid => { self.tcx.sess.span_err(span, msg);  }
+            allow => fail!(),
+        }
+
+        for note.each |&span| {
+            self.tcx.sess.span_note(span, "lint level defined here");
+        }
     }
 
     /**
@@ -308,189 +344,191 @@ pub impl Context {
      * current lint context, call the provided function, then reset the
      * lints in effect to their previous state.
      */
-    fn with_lint_attrs(&self, attrs: ~[ast::attribute], f: &fn(Context)) {
-
-        let mut new_ctxt = *self;
-        let mut triples = ~[];
-
-        for [allow, warn, deny, forbid].each |level| {
-            let level_name = level_to_str(*level);
-            let metas =
-                attr::attr_metas(attr::find_attrs_by_name(attrs, level_name));
-            for metas.each |meta| {
-                match meta.node {
-                  ast::meta_list(_, ref metas) => {
-                    for metas.each |meta| {
-                        match meta.node {
-                          ast::meta_word(ref lintname) => {
-                            triples.push((*meta,
-                                          *level,
-                                          /*bad*/copy *lintname));
-                          }
-                          _ => {
-                            self.sess.span_err(
-                                meta.span,
-                                "malformed lint attribute");
-                          }
-                        }
-                    }
-                  }
-                  _  => {
-                    self.sess.span_err(meta.span,
-                                       "malformed lint attribute");
-                  }
-                }
-            }
-        }
-
-        for triples.each |triple| {
-            // FIXME(#3874): it would be nicer to write this...
-            // let (meta, level, lintname) = /*bad*/copy *pair;
-            let (meta, level, lintname) = match *triple {
-                (ref meta, level, lintname) => (meta, level, lintname)
-            };
-
-            match self.dict.find(lintname) {
+    fn with_lint_attrs(@mut self, attrs: &[ast::attribute], f: &fn()) {
+        // Parse all of the lint attributes, and then add them all to the
+        // current dictionary of lint information. Along the way, keep a history
+        // of what we changed so we can roll everything back after invoking the
+        // specified closure
+        let mut pushed = 0u;
+        for each_lint(self.tcx.sess, attrs) |meta, level, lintname| {
+            let lint = match self.dict.find(lintname) {
               None => {
                 self.span_lint(
-                    new_ctxt.get_level(unrecognized_lint),
+                    unrecognized_lint,
                     meta.span,
                     fmt!("unknown `%s` attribute: `%s`",
                          level_to_str(level), *lintname));
+                loop
               }
-              Some(lint) => {
-
-                if new_ctxt.get_level(lint.lint) == forbid &&
-                    level != forbid {
-                    self.span_lint(
-                        forbid,
-                        meta.span,
-                        fmt!("%s(%s) overruled by outer forbid(%s)",
-                             level_to_str(level),
-                             *lintname, *lintname));
-                }
+              Some(lint) => { lint.lint }
+            };
 
-                // we do multiple unneeded copies of the
-                // map if many attributes are set, but
-                // this shouldn't actually be a problem...
+            let now = self.get_level(lint);
+            if now == forbid && level != forbid {
+                self.tcx.sess.span_err(meta.span,
+                    fmt!("%s(%s) overruled by outer forbid(%s)",
+                         level_to_str(level),
+                         *lintname, *lintname));
+                loop;
+            }
 
-                let c = clone_lint_modes(new_ctxt.curr);
-                new_ctxt = Context {
-                    is_default: false,
-                    curr: c,
-                    .. new_ctxt
-                };
-                new_ctxt.set_level(lint.lint, level);
-              }
+            if now != level {
+                let src = self.get_source(lint);
+                self.lint_stack.push((lint, now, src));
+                pushed += 1;
+                self.set_level(lint, level, Node(meta.span));
             }
         }
-        f(new_ctxt);
-    }
-}
 
+        f();
 
-fn build_settings_item(i: @ast::item, cx: Context, v: visit::vt<Context>) {
-    do cx.with_lint_attrs(/*bad*/copy i.attrs) |cx| {
-        if !cx.is_default {
-            cx.sess.lint_settings.settings_map.insert(i.id, cx.curr);
+        // rollback
+        for pushed.times {
+            let (lint, lvl, src) = self.lint_stack.pop();
+            self.set_level(lint, lvl, src);
         }
-        visit::visit_item(i, cx, v);
     }
-}
-
-pub fn build_settings_crate(sess: session::Session, crate: @ast::crate) {
-    let cx = Context {
-        dict: get_lint_dict(),
-        curr: @mut SmallIntMap::new(),
-        is_default: true,
-        sess: sess
-    };
 
-    // Install defaults.
-    for cx.dict.each_value |&spec| {
-        cx.set_level(spec.lint, spec.default);
+    fn add_lint(&mut self, v: visit::vt<()>) {
+        self.visitors.push(item_stopping_visitor(v));
     }
 
-    // Install command-line options, overriding defaults.
-    for sess.opts.lint_opts.each |pair| {
-        let (lint,level) = *pair;
-        cx.set_level(lint, level);
+    fn process(&self, n: AttributedNode) {
+        match n {
+            Item(it) => {
+                for self.visitors.each |v| {
+                    visit::visit_item(it, (), *v);
+                }
+            }
+            Crate(c) => {
+                for self.visitors.each |v| {
+                    visit::visit_crate(c, (), *v);
+                }
+            }
+            // Can't use visit::visit_method_helper because the
+            // item_stopping_visitor has overridden visit_fn(&fk_method(... ))
+            // to be a no-op, so manually invoke visit_fn.
+            Method(m) => {
+                let fk = visit::fk_method(copy m.ident, &m.generics, m);
+                for self.visitors.each |v| {
+                    visit::visit_fn(&fk, &m.decl, &m.body, m.span, m.id,
+                                    (), *v);
+                }
+            }
+        }
     }
+}
 
-    do cx.with_lint_attrs(/*bad*/copy crate.node.attrs) |cx| {
-        // Copy out the default settings
-        for cx.curr.each |&k, &v| {
-            sess.lint_settings.default_settings.insert(k, v);
+#[cfg(stage0)]
+pub fn each_lint(sess: session::Session,
+                 attrs: &[ast::attribute],
+                 f: &fn(@ast::meta_item, level, &~str) -> bool)
+{
+    for [allow, warn, deny, forbid].each |&level| {
+        let level_name = level_to_str(level);
+        let attrs = attr::find_attrs_by_name(attrs, level_name);
+        for attrs.each |attr| {
+            let meta = attr.node.value;
+            let metas = match meta.node {
+                ast::meta_list(_, ref metas) => metas,
+                _ => {
+                    sess.span_err(meta.span, ~"malformed lint attribute");
+                    loop;
+                }
+            };
+            for metas.each |meta| {
+                match meta.node {
+                    ast::meta_word(lintname) => {
+                        if !f(*meta, level, lintname) {
+                            return;
+                        }
+                    }
+                    _ => {
+                        sess.span_err(meta.span, ~"malformed lint attribute");
+                    }
+                }
+            }
         }
-
-        let cx = Context {
-            is_default: true,
-            .. cx
-        };
-
-        let visit = visit::mk_vt(@visit::Visitor {
-            visit_item: build_settings_item,
-            .. *visit::default_visitor()
-        });
-        visit::visit_crate(crate, cx, visit);
     }
-
-    sess.abort_if_errors();
 }
-
-fn check_item(i: @ast::item, cx: ty::ctxt) {
-    check_item_ctypes(cx, i);
-    check_item_while_true(cx, i);
-    check_item_path_statement(cx, i);
-    check_item_non_camel_case_types(cx, i);
-    check_item_heap(cx, i);
-    check_item_type_limits(cx, i);
-    check_item_default_methods(cx, i);
-    check_item_unused_unsafe(cx, i);
-    check_item_unused_mut(cx, i);
+#[cfg(not(stage0))]
+pub fn each_lint(sess: session::Session,
+                 attrs: &[ast::attribute],
+                 f: &fn(@ast::meta_item, level, &~str) -> bool) -> bool
+{
+    for [allow, warn, deny, forbid].each |&level| {
+        let level_name = level_to_str(level);
+        let attrs = attr::find_attrs_by_name(attrs, level_name);
+        for attrs.each |attr| {
+            let meta = attr.node.value;
+            let metas = match meta.node {
+                ast::meta_list(_, ref metas) => metas,
+                _ => {
+                    sess.span_err(meta.span, ~"malformed lint attribute");
+                    loop;
+                }
+            };
+            for metas.each |meta| {
+                match meta.node {
+                    ast::meta_word(lintname) => {
+                        if !f(*meta, level, lintname) {
+                            return false;
+                        }
+                    }
+                    _ => {
+                        sess.span_err(meta.span, ~"malformed lint attribute");
+                    }
+                }
+            }
+        }
+    }
+    return true;
 }
 
 // Take a visitor, and modify it so that it will not proceed past subitems.
 // This is used to make the simple visitors used for the lint passes
 // not traverse into subitems, since that is handled by the outer
 // lint visitor.
-fn item_stopping_visitor<E>(v: visit::vt<E>) -> visit::vt<E> {
-    visit::mk_vt(@visit::Visitor {visit_item: |_i, _e, _v| { },
-        .. **(ty_stopping_visitor(v))})
+fn item_stopping_visitor<E: Copy>(v: visit::vt<E>) -> visit::vt<E> {
+    visit::mk_vt(@visit::Visitor {
+        visit_item: |_i, _e, _v| { },
+        visit_fn: |fk, fd, b, s, id, e, v| {
+            match *fk {
+                visit::fk_method(*) => {}
+                _ => visit::visit_fn(fk, fd, b, s, id, e, v)
+            }
+        },
+    .. **(ty_stopping_visitor(v))})
 }
 
 fn ty_stopping_visitor<E>(v: visit::vt<E>) -> visit::vt<E> {
     visit::mk_vt(@visit::Visitor {visit_ty: |_t, _e, _v| { },.. **v})
 }
 
-fn check_item_while_true(cx: ty::ctxt, it: @ast::item) {
-    let visit = item_stopping_visitor(
-        visit::mk_simple_visitor(@visit::SimpleVisitor {
-            visit_expr: |e: @ast::expr| {
-                match e.node {
-                    ast::expr_while(cond, _) => {
-                        match cond.node {
-                            ast::expr_lit(@codemap::spanned {
-                                node: ast::lit_bool(true), _}) =>
-                            {
-                                cx.sess.span_lint(
-                                    while_true, e.id, it.id,
-                                    e.span,
-                                    "denote infinite loops \
-                                     with loop { ... }");
-                            }
-                            _ => ()
+fn lint_while_true(cx: @mut Context) -> visit::vt<()> {
+    visit::mk_simple_visitor(@visit::SimpleVisitor {
+        visit_expr: |e: @ast::expr| {
+            match e.node {
+                ast::expr_while(cond, _) => {
+                    match cond.node {
+                        ast::expr_lit(@codemap::spanned {
+                            node: ast::lit_bool(true), _}) =>
+                        {
+                            cx.span_lint(while_true, e.span,
+                                         "denote infinite loops with \
+                                          loop { ... }");
                         }
+                        _ => ()
                     }
-                    _ => ()
                 }
-            },
-            .. *visit::default_simple_visitor()
-        }));
-    visit::visit_item(it, (), visit);
+                _ => ()
+            }
+        },
+        .. *visit::default_simple_visitor()
+    })
 }
 
-fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) {
+fn lint_type_limits(cx: @mut Context) -> visit::vt<()> {
     fn is_valid<T:cmp::Ord>(binop: ast::binop, v: T,
             min: T, max: T) -> bool {
         match binop {
@@ -513,9 +551,11 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) {
         }
     }
 
+    // for int & uint, be conservative with the warnings, so that the
+    // warnings are consistent between 32- and 64-bit platforms
     fn int_ty_range(int_ty: ast::int_ty) -> (i64, i64) {
         match int_ty {
-            ast::ty_i =>    (int::min_value as i64, int::max_value as i64),
+            ast::ty_i =>    (i64::min_value,        i64::max_value),
             ast::ty_char => (u32::min_value as i64, u32::max_value as i64),
             ast::ty_i8 =>   (i8::min_value  as i64, i8::max_value  as i64),
             ast::ty_i16 =>  (i16::min_value as i64, i16::max_value as i64),
@@ -526,7 +566,7 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) {
 
     fn uint_ty_range(uint_ty: ast::uint_ty) -> (u64, u64) {
         match uint_ty {
-            ast::ty_u =>   (uint::min_value as u64, uint::max_value as u64),
+            ast::ty_u =>   (u64::min_value,         u64::max_value),
             ast::ty_u8 =>  (u8::min_value   as u64, u8::max_value   as u64),
             ast::ty_u16 => (u16::min_value  as u64, u16::max_value  as u64),
             ast::ty_u32 => (u32::min_value  as u64, u32::max_value  as u64),
@@ -534,7 +574,7 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) {
         }
     }
 
-    fn check_limits(cx: ty::ctxt, binop: ast::binop, l: &ast::expr,
+    fn check_limits(cx: @mut Context, binop: ast::binop, l: &ast::expr,
                     r: &ast::expr) -> bool {
         let (lit, expr, swap) = match (&l.node, &r.node) {
             (&ast::expr_lit(_), _) => (l, r, true),
@@ -543,12 +583,12 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) {
         };
         // Normalize the binop so that the literal is always on the RHS in
         // the comparison
-        let norm_binop = if (swap) {
+        let norm_binop = if swap {
             rev_binop(binop)
         } else {
             binop
         };
-        match ty::get(ty::expr_ty(cx, @/*bad*/copy *expr)).sty {
+        match ty::get(ty::expr_ty(cx.tcx, @/*bad*/copy *expr)).sty {
             ty::ty_int(int_ty) => {
                 let (min, max) = int_ty_range(int_ty);
                 let lit_val: i64 = match lit.node {
@@ -592,36 +632,29 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) {
             ast::expr_binary(ref binop, @ref l, @ref r) => {
                 if is_comparison(*binop)
                     && !check_limits(cx, *binop, l, r) {
-                    cx.sess.span_lint(
-                        type_limits, e.id, it.id, e.span,
-                        "comparison is useless due to type limits");
+                    cx.span_lint(type_limits, e.span,
+                                 "comparison is useless due to type limits");
                 }
             }
             _ => ()
         }
     };
 
-    let visit = item_stopping_visitor(
-        visit::mk_simple_visitor(@visit::SimpleVisitor {
-            visit_expr: visit_expr,
-            .. *visit::default_simple_visitor()
-        }));
-    visit::visit_item(it, (), visit);
+    visit::mk_simple_visitor(@visit::SimpleVisitor {
+        visit_expr: visit_expr,
+        .. *visit::default_simple_visitor()
+    })
 }
 
-fn check_item_default_methods(cx: ty::ctxt, item: @ast::item) {
+fn check_item_default_methods(cx: @mut Context, item: @ast::item) {
     match item.node {
         ast::item_trait(_, _, ref methods) => {
             for methods.each |method| {
                 match *method {
                     ast::required(*) => {}
                     ast::provided(*) => {
-                        cx.sess.span_lint(
-                            default_methods,
-                            item.id,
-                            item.id,
-                            item.span,
-                            "default methods are experimental");
+                        cx.span_lint(default_methods, item.span,
+                                     "default methods are experimental");
                     }
                 }
             }
@@ -630,25 +663,21 @@ fn check_item_default_methods(cx: ty::ctxt, item: @ast::item) {
     }
 }
 
-fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) {
-    fn check_foreign_fn(cx: ty::ctxt, fn_id: ast::node_id,
-                        decl: &ast::fn_decl) {
+fn check_item_ctypes(cx: @mut Context, it: @ast::item) {
+
+    fn check_foreign_fn(cx: @mut Context, decl: &ast::fn_decl) {
         let tys = vec::map(decl.inputs, |a| a.ty );
         for vec::each(vec::append_one(tys, decl.output)) |ty| {
             match ty.node {
               ast::ty_path(_, id) => {
-                match cx.def_map.get_copy(&id) {
+                match cx.tcx.def_map.get_copy(&id) {
                   ast::def_prim_ty(ast::ty_int(ast::ty_i)) => {
-                    cx.sess.span_lint(
-                        ctypes, id, fn_id,
-                        ty.span,
+                    cx.span_lint(ctypes, ty.span,
                         "found rust type `int` in foreign module, while \
                          libc::c_int or libc::c_long should be used");
                   }
                   ast::def_prim_ty(ast::ty_uint(ast::ty_u)) => {
-                    cx.sess.span_lint(
-                        ctypes, id, fn_id,
-                        ty.span,
+                    cx.span_lint(ctypes, ty.span,
                         "found rust type `uint` in foreign module, while \
                          libc::c_uint or libc::c_ulong should be used");
                   }
@@ -665,7 +694,7 @@ fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) {
         for nmod.items.each |ni| {
             match ni.node {
               ast::foreign_item_fn(ref decl, _, _) => {
-                check_foreign_fn(cx, it.id, decl);
+                check_foreign_fn(cx, decl);
               }
               // FIXME #4622: Not implemented.
               ast::foreign_item_const(*) => {}
@@ -676,57 +705,47 @@ fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) {
     }
 }
 
-fn check_item_heap(cx: ty::ctxt, it: @ast::item) {
-
-    fn check_type_for_lint(cx: ty::ctxt, lint: lint,
-                           node: ast::node_id,
-                           item: ast::node_id,
-                           span: span, ty: ty::t) {
-
-        if get_lint_settings_level(cx.sess.lint_settings,
-                                   lint, node, item) != allow {
-            let mut n_box = 0;
-            let mut n_uniq = 0;
-            ty::fold_ty(cx, ty, |t| {
-                match ty::get(t).sty {
-                  ty::ty_box(_) => n_box += 1,
-                  ty::ty_uniq(_) => n_uniq += 1,
-                  _ => ()
-                };
-                t
-            });
+fn check_type_for_lint(cx: @mut Context, lint: lint, span: span, ty: ty::t) {
+    if cx.get_level(lint) == allow { return }
 
-            if (n_uniq > 0 && lint != managed_heap_memory) {
-                let s = ty_to_str(cx, ty);
-                let m = ~"type uses owned (~ type) pointers: " + s;
-                cx.sess.span_lint(lint, node, item, span, m);
-            }
+    let mut n_box = 0;
+    let mut n_uniq = 0;
+    ty::fold_ty(cx.tcx, ty, |t| {
+        match ty::get(t).sty {
+          ty::ty_box(_) => n_box += 1,
+          ty::ty_uniq(_) => n_uniq += 1,
+          _ => ()
+        };
+        t
+    });
 
-            if (n_box > 0 && lint != owned_heap_memory) {
-                let s = ty_to_str(cx, ty);
-                let m = ~"type uses managed (@ type) pointers: " + s;
-                cx.sess.span_lint(lint, node, item, span, m);
-            }
-        }
+    if n_uniq > 0 && lint != managed_heap_memory {
+        let s = ty_to_str(cx.tcx, ty);
+        let m = ~"type uses owned (~ type) pointers: " + s;
+        cx.span_lint(lint, span, m);
     }
 
-    fn check_type(cx: ty::ctxt,
-                  node: ast::node_id,
-                  item: ast::node_id,
-                  span: span, ty: ty::t) {
-            for [managed_heap_memory,
-                 owned_heap_memory,
-                 heap_memory].each |lint| {
-                check_type_for_lint(cx, *lint, node, item, span, ty);
-            }
+    if n_box > 0 && lint != owned_heap_memory {
+        let s = ty_to_str(cx.tcx, ty);
+        let m = ~"type uses managed (@ type) pointers: " + s;
+        cx.span_lint(lint, span, m);
     }
+}
+
+fn check_type(cx: @mut Context, span: span, ty: ty::t) {
+    for [managed_heap_memory, owned_heap_memory, heap_memory].each |lint| {
+        check_type_for_lint(cx, *lint, span, ty);
+    }
+}
 
+fn check_item_heap(cx: @mut Context, it: @ast::item) {
     match it.node {
       ast::item_fn(*) |
       ast::item_ty(*) |
       ast::item_enum(*) |
-      ast::item_struct(*) => check_type(cx, it.id, it.id, it.span,
-                                       ty::node_id_to_type(cx, it.id)),
+      ast::item_struct(*) => check_type(cx, it.span,
+                                        ty::node_id_to_type(cx.tcx,
+                                                            it.id)),
       _ => ()
     }
 
@@ -734,48 +753,44 @@ fn check_item_heap(cx: ty::ctxt, it: @ast::item) {
     match it.node {
         ast::item_struct(struct_def, _) => {
             for struct_def.fields.each |struct_field| {
-                check_type(cx, struct_field.node.id, it.id,
-                           struct_field.span,
-                           ty::node_id_to_type(cx, struct_field.node.id));
+                check_type(cx, struct_field.span,
+                           ty::node_id_to_type(cx.tcx,
+                                               struct_field.node.id));
             }
         }
         _ => ()
     }
+}
 
-    let visit = item_stopping_visitor(
-        visit::mk_simple_visitor(@visit::SimpleVisitor {
-            visit_expr: |e: @ast::expr| {
-                let ty = ty::expr_ty(cx, e);
-                check_type(cx, e.id, it.id, e.span, ty);
-            },
-            .. *visit::default_simple_visitor()
-        }));
-    visit::visit_item(it, (), visit);
+fn lint_heap(cx: @mut Context) -> visit::vt<()> {
+    visit::mk_simple_visitor(@visit::SimpleVisitor {
+        visit_expr: |e| {
+            let ty = ty::expr_ty(cx.tcx, e);
+            check_type(cx, e.span, ty);
+        },
+        .. *visit::default_simple_visitor()
+    })
 }
 
-fn check_item_path_statement(cx: ty::ctxt, it: @ast::item) {
-    let visit = item_stopping_visitor(
-        visit::mk_simple_visitor(@visit::SimpleVisitor {
-            visit_stmt: |s: @ast::stmt| {
-                match s.node {
-                    ast::stmt_semi(
-                        @ast::expr { id: id, node: ast::expr_path(_), _ },
-                        _
-                    ) => {
-                        cx.sess.span_lint(
-                            path_statement, id, it.id,
-                            s.span,
-                            "path statement with no effect");
-                    }
-                    _ => ()
+fn lint_path_statement(cx: @mut Context) -> visit::vt<()> {
+    visit::mk_simple_visitor(@visit::SimpleVisitor {
+        visit_stmt: |s| {
+            match s.node {
+                ast::stmt_semi(
+                    @ast::expr { node: ast::expr_path(_), _ },
+                    _
+                ) => {
+                    cx.span_lint(path_statement, s.span,
+                                 "path statement with no effect");
                 }
-            },
-            .. *visit::default_simple_visitor()
-        }));
-    visit::visit_item(it, (), visit);
+                _ => ()
+            }
+        },
+        .. *visit::default_simple_visitor()
+    })
 }
 
-fn check_item_non_camel_case_types(cx: ty::ctxt, it: @ast::item) {
+fn check_item_non_camel_case_types(cx: @mut Context, it: @ast::item) {
     fn is_camel_case(cx: ty::ctxt, ident: ast::ident) -> bool {
         let ident = cx.sess.str_of(ident);
         assert!(!ident.is_empty());
@@ -799,61 +814,54 @@ fn check_item_non_camel_case_types(cx: ty::ctxt, it: @ast::item) {
         }
     }
 
-    fn check_case(cx: ty::ctxt, ident: ast::ident,
-                  expr_id: ast::node_id, item_id: ast::node_id,
-                  span: span) {
-        if !is_camel_case(cx, ident) {
-            cx.sess.span_lint(
-                non_camel_case_types, expr_id, item_id, span,
-                "type, variant, or trait should have \
-                 a camel case identifier");
+    fn check_case(cx: @mut Context, ident: ast::ident, span: span) {
+        if !is_camel_case(cx.tcx, ident) {
+            cx.span_lint(non_camel_case_types, span,
+                         "type, variant, or trait should have \
+                          a camel case identifier");
         }
     }
 
     match it.node {
         ast::item_ty(*) | ast::item_struct(*) |
         ast::item_trait(*) => {
-            check_case(cx, it.ident, it.id, it.id, it.span)
+            check_case(cx, it.ident, it.span)
         }
         ast::item_enum(ref enum_definition, _) => {
-            check_case(cx, it.ident, it.id, it.id, it.span);
+            check_case(cx, it.ident, it.span);
             for enum_definition.variants.each |variant| {
-                check_case(cx, variant.node.name,
-                           variant.node.id, it.id, variant.span);
+                check_case(cx, variant.node.name, variant.span);
             }
         }
         _ => ()
     }
 }
 
-fn check_item_unused_unsafe(cx: ty::ctxt, it: @ast::item) {
+fn lint_unused_unsafe(cx: @mut Context) -> visit::vt<()> {
     let visit_expr: @fn(@ast::expr) = |e| {
         match e.node {
             ast::expr_block(ref blk) if blk.node.rules == ast::unsafe_blk => {
-                if !cx.used_unsafe.contains(&blk.node.id) {
-                    cx.sess.span_lint(unused_unsafe, blk.node.id, it.id,
-                                      blk.span,
-                                      "unnecessary `unsafe` block");
+                if !cx.tcx.used_unsafe.contains(&blk.node.id) {
+                    cx.span_lint(unused_unsafe, blk.span,
+                                 "unnecessary `unsafe` block");
                 }
             }
             _ => ()
         }
     };
 
-    let visit = item_stopping_visitor(
-        visit::mk_simple_visitor(@visit::SimpleVisitor {
-            visit_expr: visit_expr,
-            .. *visit::default_simple_visitor()
-        }));
-    visit::visit_item(it, (), visit);
+    visit::mk_simple_visitor(@visit::SimpleVisitor {
+        visit_expr: visit_expr,
+        .. *visit::default_simple_visitor()
+    })
 }
 
-fn check_item_unused_mut(tcx: ty::ctxt, it: @ast::item) {
+fn lint_unused_mut(cx: @mut Context) -> visit::vt<()> {
     let check_pat: @fn(@ast::pat) = |p| {
         let mut used = false;
         let mut bindings = 0;
-        do pat_util::pat_bindings(tcx.def_map, p) |_, id, _, _| {
-            used = used || tcx.used_mut_nodes.contains(&id);
+        do pat_util::pat_bindings(cx.tcx.def_map, p) |_, id, _, _| {
+            used = used || cx.tcx.used_mut_nodes.contains(&id);
             bindings += 1;
         }
         if !used {
@@ -862,7 +870,7 @@ fn check_item_unused_mut(tcx: ty::ctxt, it: @ast::item) {
             } else {
                 "variables do not need to be mutable"
             };
-            tcx.sess.span_lint(unused_mut, p.id, it.id, p.span, msg);
+            cx.span_lint(unused_mut, p.span, msg);
         }
     };
 
@@ -874,45 +882,116 @@ fn check_item_unused_mut(tcx: ty::ctxt, it: @ast::item) {
         }
     };
 
-    let visit = item_stopping_visitor(
-        visit::mk_simple_visitor(@visit::SimpleVisitor {
-            visit_local: |l| {
-                if l.node.is_mutbl {
-                    check_pat(l.node.pat);
-                }
-            },
-            visit_fn: |_, fd, _, _, _| visit_fn_decl(fd),
-            visit_ty_method: |tm| visit_fn_decl(&tm.decl),
-            visit_struct_method: |sm| visit_fn_decl(&sm.decl),
-            visit_trait_method: |tm| {
-                match *tm {
-                    ast::required(ref tm) => visit_fn_decl(&tm.decl),
-                    ast::provided(m) => visit_fn_decl(&m.decl),
-                }
-            },
-            .. *visit::default_simple_visitor()
-        }));
-    visit::visit_item(it, (), visit);
+    visit::mk_simple_visitor(@visit::SimpleVisitor {
+        visit_local: |l| {
+            if l.node.is_mutbl {
+                check_pat(l.node.pat);
+            }
+        },
+        visit_fn: |_, fd, _, _, _| visit_fn_decl(fd),
+        visit_ty_method: |tm| visit_fn_decl(&tm.decl),
+        visit_struct_method: |sm| visit_fn_decl(&sm.decl),
+        visit_trait_method: |tm| {
+            match *tm {
+                ast::required(ref tm) => visit_fn_decl(&tm.decl),
+                ast::provided(m) => visit_fn_decl(&m.decl),
+            }
+        },
+        .. *visit::default_simple_visitor()
+    })
 }
 
-fn check_fn(_: ty::ctxt,
-            fk: &visit::fn_kind,
-            _: &ast::fn_decl,
-            _: &ast::blk,
-            _: span,
-            id: ast::node_id) {
-    debug!("lint check_fn fk=%? id=%?", fk, id);
+fn lint_session(cx: @mut Context) -> visit::vt<()> {
+    ast_util::id_visitor(|id| {
+        match cx.tcx.sess.lints.pop(&id) {
+            None => {},
+            Some(l) => {
+                do vec::consume(l) |_, (lint, span, msg)| {
+                    cx.span_lint(lint, span, msg)
+                }
+            }
+        }
+    })
 }
 
 pub fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
-    let v = visit::mk_simple_visitor(@visit::SimpleVisitor {
-        visit_item: |it|
-            check_item(it, tcx),
-        visit_fn: |fk, decl, body, span, id|
-            check_fn(tcx, fk, decl, body, span, id),
-        .. *visit::default_simple_visitor()
-    });
-    visit::visit_crate(crate, (), v);
+    let cx = @mut Context {
+        dict: @get_lint_dict(),
+        curr: SmallIntMap::new(),
+        tcx: tcx,
+        lint_stack: ~[],
+        visitors: ~[],
+    };
+
+    // Install defaults.
+    for cx.dict.each_value |spec| {
+        cx.set_level(spec.lint, spec.default, Default);
+    }
+
+    // Install command-line options, overriding defaults.
+    for tcx.sess.opts.lint_opts.each |&(lint, level)| {
+        cx.set_level(lint, level, CommandLine);
+    }
+
+    // Register each of the lint passes with the context
+    cx.add_lint(lint_while_true(cx));
+    cx.add_lint(lint_path_statement(cx));
+    cx.add_lint(lint_heap(cx));
+    cx.add_lint(lint_type_limits(cx));
+    cx.add_lint(lint_unused_unsafe(cx));
+    cx.add_lint(lint_unused_mut(cx));
+    cx.add_lint(lint_session(cx));
+
+    // type inference doesn't like this being declared below, we need to tell it
+    // what the type of this first function is...
+    let visit_item:
+        @fn(@ast::item, @mut Context, visit::vt<@mut Context>) =
+    |it, cx, vt| {
+        do cx.with_lint_attrs(it.attrs) {
+            check_item_ctypes(cx, it);
+            check_item_non_camel_case_types(cx, it);
+            check_item_default_methods(cx, it);
+            check_item_heap(cx, it);
+
+            cx.process(Item(it));
+            visit::visit_item(it, cx, vt);
+        }
+    };
+
+    // Actually perform the lint checks (iterating the ast)
+    do cx.with_lint_attrs(crate.node.attrs) {
+        cx.process(Crate(crate));
+
+        visit::visit_crate(crate, cx, visit::mk_vt(@visit::Visitor {
+            visit_item: visit_item,
+            visit_fn: |fk, decl, body, span, id, cx, vt| {
+                match *fk {
+                    visit::fk_method(_, _, m) => {
+                        do cx.with_lint_attrs(m.attrs) {
+                            cx.process(Method(m));
+                            visit::visit_fn(fk, decl, body, span, id, cx, vt);
+                        }
+                    }
+                    _ => {
+                        visit::visit_fn(fk, decl, body, span, id, cx, vt);
+                    }
+                }
+            },
+            .. *visit::default_visitor()
+        }));
+    }
+
+    // If we missed any lints added to the session, then there's a bug somewhere
+    // in the iteration code.
+    for tcx.sess.lints.each |_, v| {
+        for v.each |t| {
+            match *t {
+                (lint, span, ref msg) =>
+                    tcx.sess.span_bug(span, fmt!("unprocessed lint %?: %s",
+                                                 lint, *msg))
+            }
+        }
+    }
 
     tcx.sess.abort_if_errors();
 }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 9995de24e8d..711e3915277 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -153,15 +153,13 @@ pub fn check_crate(tcx: ty::ctxt,
         visit_local: visit_local,
         visit_expr: visit_expr,
         visit_arm: visit_arm,
-        visit_item: visit_item,
         .. *visit::default_visitor()
     });
 
     let initial_maps = @mut IrMaps(tcx,
                                    method_map,
                                    variable_moves_map,
-                                   capture_map,
-                                   0);
+                                   capture_map);
     visit::visit_crate(crate, initial_maps, visitor);
     tcx.sess.abort_if_errors();
 }
@@ -240,15 +238,12 @@ struct IrMaps {
     capture_info_map: HashMap<node_id, @~[CaptureInfo]>,
     var_kinds: ~[VarKind],
     lnks: ~[LiveNodeKind],
-
-    cur_item: node_id,
 }
 
 fn IrMaps(tcx: ty::ctxt,
           method_map: typeck::method_map,
           variable_moves_map: moves::VariableMovesMap,
-          capture_map: moves::CaptureMap,
-          cur_item: node_id)
+          capture_map: moves::CaptureMap)
        -> IrMaps {
     IrMaps {
         tcx: tcx,
@@ -262,7 +257,6 @@ fn IrMaps(tcx: ty::ctxt,
         capture_info_map: HashMap::new(),
         var_kinds: ~[],
         lnks: ~[],
-        cur_item: cur_item,
     }
 }
 
@@ -341,13 +335,6 @@ pub impl IrMaps {
     }
 }
 
-fn visit_item(item: @item, this: @mut IrMaps, v: vt<@mut IrMaps>) {
-    let old_cur_item = this.cur_item;
-    this.cur_item = item.id;
-    visit::visit_item(item, this, v);
-    this.cur_item = old_cur_item;
-}
-
 fn visit_fn(fk: &visit::fn_kind,
             decl: &fn_decl,
             body: &blk,
@@ -362,8 +349,7 @@ fn visit_fn(fk: &visit::fn_kind,
     let fn_maps = @mut IrMaps(this.tcx,
                               this.method_map,
                               this.variable_moves_map,
-                              this.capture_map,
-                              this.cur_item);
+                              this.capture_map);
 
     unsafe {
         debug!("creating fn_maps: %x", transmute(&*fn_maps));
@@ -1802,13 +1788,11 @@ pub impl Liveness {
                 };
 
                 if is_assigned {
-                    self.tcx.sess.span_lint(unused_variable, id,
-                        self.ir.cur_item, sp,
+                    self.tcx.sess.add_lint(unused_variable, id, sp,
                         fmt!("variable `%s` is assigned to, \
                                   but never used", **name));
                 } else {
-                    self.tcx.sess.span_lint(unused_variable, id,
-                        self.ir.cur_item, sp,
+                    self.tcx.sess.add_lint(unused_variable, id, sp,
                         fmt!("unused variable: `%s`", **name));
                 }
             }
@@ -1821,8 +1805,7 @@ pub impl Liveness {
                               ln: LiveNode, var: Variable) {
         if self.live_on_exit(ln, var).is_none() {
             for self.should_warn(var).each |name| {
-                self.tcx.sess.span_lint(dead_assignment, id,
-                    self.ir.cur_item, sp,
+                self.tcx.sess.add_lint(dead_assignment, id, sp,
                     fmt!("value assigned to `%s` is never read", **name));
             }
         }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 95ed7fe8efc..91c0b8e61cc 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -551,7 +551,7 @@ pub impl mem_categorization_ctxt {
             id:elt.id(),
             span:elt.span(),
             cat:cat_rvalue,
-            mutbl:McImmutable,
+            mutbl:McDeclared,
             ty:expr_ty
         }
     }
diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs
index 3a2fb654006..e81a9d6b78f 100644
--- a/src/librustc/middle/moves.rs
+++ b/src/librustc/middle/moves.rs
@@ -221,16 +221,14 @@ use syntax::visit::vt;
 use syntax::print::pprust;
 use syntax::codemap::span;
 
-#[auto_encode]
-#[auto_decode]
+#[deriving(Encodable, Decodable)]
 pub enum CaptureMode {
     CapCopy, // Copy the value into the closure.
     CapMove, // Move the value into the closure.
     CapRef,  // Reference directly from parent stack frame (used by `&fn()`).
 }
 
-#[auto_encode]
-#[auto_decode]
+#[deriving(Encodable, Decodable)]
 pub struct CaptureVar {
     def: def,         // Variable being accessed free
     span: span,       // Location of an access to this variable
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 9b864bd0ef2..a7e590e359c 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -16,46 +16,10 @@ use metadata::csearch::get_type_name_if_impl;
 use metadata::cstore::find_extern_mod_stmt_cnum;
 use metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
 use middle::lang_items::LanguageItems;
-use middle::lint::{allow, level, unused_imports};
-use middle::lint::{get_lint_level, get_lint_settings_level};
+use middle::lint::unused_imports;
 use middle::pat_util::pat_bindings;
 
-use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm};
-use syntax::ast::{binding_mode, bitand, bitor, bitxor, blk};
-use syntax::ast::{bind_infer, bind_by_ref, bind_by_copy};
-use syntax::ast::{crate, decl_item, def, def_arg, def_binding};
-use syntax::ast::{def_const, def_foreign_mod, def_fn, def_id, def_label};
-use syntax::ast::{def_local, def_mod, def_prim_ty, def_region, def_self};
-use syntax::ast::{def_self_ty, def_static_method, def_struct, def_ty};
-use syntax::ast::{def_ty_param, def_typaram_binder, def_trait};
-use syntax::ast::{def_upvar, def_use, def_variant, explicit_self_, expr, expr_assign_op};
-use syntax::ast::{expr_binary, expr_break, expr_field};
-use syntax::ast::{expr_fn_block, expr_index, expr_method_call, expr_path};
-use syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param};
-use syntax::ast::{def_upvar, def_use, def_variant, div, eq};
-use syntax::ast::{expr, expr_again, expr_assign_op};
-use syntax::ast::{expr_index, expr_loop};
-use syntax::ast::{expr_path, expr_self, expr_struct, expr_unary, fn_decl};
-use syntax::ast::{foreign_item, foreign_item_const, foreign_item_fn, ge};
-use syntax::ast::Generics;
-use syntax::ast::{gt, ident, inherited, item, item_struct};
-use syntax::ast::{item_const, item_enum, item_fn, item_foreign_mod};
-use syntax::ast::{item_impl, item_mac, item_mod, item_trait, item_ty, le};
-use syntax::ast::{local, local_crate, lt, method, mul};
-use syntax::ast::{named_field, ne, neg, node_id, pat, pat_enum, pat_ident};
-use syntax::ast::{Path, pat_lit, pat_range, pat_struct};
-use syntax::ast::{prim_ty, private, provided};
-use syntax::ast::{public, required, rem, shl, shr, stmt_decl};
-use syntax::ast::{struct_field, struct_variant_kind};
-use syntax::ast::{sty_static, subtract, trait_ref, tuple_variant_kind, Ty};
-use syntax::ast::{ty_bool, ty_char, ty_f, ty_f32, ty_f64, ty_float, ty_i};
-use syntax::ast::{ty_i16, ty_i32, ty_i64, ty_i8, ty_int, TyParam, ty_path};
-use syntax::ast::{ty_str, ty_u, ty_u16, ty_u32, ty_u64, ty_u8, ty_uint};
-use syntax::ast::unnamed_field;
-use syntax::ast::{variant, view_item, view_item_extern_mod};
-use syntax::ast::{view_item_use, view_path_glob, view_path_list};
-use syntax::ast::{view_path_simple, anonymous, named, not};
-use syntax::ast::{unsafe_fn};
+use syntax::ast::*;
 use syntax::ast_util::{def_id_of_def, local_def};
 use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method};
 use syntax::ast_util::{Privacy, Public, Private};
@@ -65,6 +29,7 @@ use syntax::parse::token::ident_interner;
 use syntax::parse::token::special_idents;
 use syntax::print::pprust::path_to_str;
 use syntax::codemap::{span, dummy_sp, BytePos};
+use syntax::visit::{mk_simple_visitor, default_simple_visitor, SimpleVisitor};
 use syntax::visit::{default_visitor, mk_vt, Visitor, visit_block};
 use syntax::visit::{visit_crate, visit_expr, visit_expr_opt};
 use syntax::visit::{visit_foreign_item, visit_item};
@@ -345,18 +310,21 @@ pub struct ImportDirective {
     module_path: ~[ident],
     subclass: @ImportDirectiveSubclass,
     span: span,
+    id: node_id,
 }
 
 pub fn ImportDirective(privacy: Privacy,
                        module_path: ~[ident],
                        subclass: @ImportDirectiveSubclass,
-                       span: span)
+                       span: span,
+                       id: node_id)
                     -> ImportDirective {
     ImportDirective {
         privacy: privacy,
         module_path: module_path,
         subclass: subclass,
-        span: span
+        span: span,
+        id: id
     }
 }
 
@@ -380,7 +348,7 @@ pub struct ImportResolution {
     /// The privacy of this `use` directive (whether it's `use` or
     /// `pub use`.
     privacy: Privacy,
-    span: span,
+    id: node_id,
 
     // The number of outstanding references to this name. When this reaches
     // zero, outside modules can count on the targets being correct. Before
@@ -392,21 +360,16 @@ pub struct ImportResolution {
     value_target: Option<Target>,
     /// The type that this `use` directive names, if there is one.
     type_target: Option<Target>,
-
-    /// There exists one state per import statement
-    state: @mut ImportState,
 }
 
 pub fn ImportResolution(privacy: Privacy,
-                        span: span,
-                        state: @mut ImportState) -> ImportResolution {
+                        id: node_id) -> ImportResolution {
     ImportResolution {
         privacy: privacy,
-        span: span,
+        id: id,
         outstanding_references: 0,
         value_target: None,
         type_target: None,
-        state: state,
     }
 }
 
@@ -419,15 +382,6 @@ pub impl ImportResolution {
     }
 }
 
-pub struct ImportState {
-    used: bool,
-    warned: bool
-}
-
-pub fn ImportState() -> ImportState {
-    ImportState{ used: false, warned: false }
-}
-
 /// The link from a module up to its nearest parent node.
 pub enum ParentLink {
     NoParentLink,
@@ -512,13 +466,15 @@ pub impl Module {
 pub struct TypeNsDef {
     privacy: Privacy,
     module_def: Option<@mut Module>,
-    type_def: Option<def>
+    type_def: Option<def>,
+    type_span: Option<span>
 }
 
 // Records a possibly-private value definition.
 pub struct ValueNsDef {
     privacy: Privacy,
     def: def,
+    value_span: Option<span>,
 }
 
 // Records the definitions (at most one for each namespace) that a name is
@@ -526,11 +482,6 @@ pub struct ValueNsDef {
 pub struct NameBindings {
     type_def: Option<TypeNsDef>,    //< Meaning in type namespace.
     value_def: Option<ValueNsDef>,  //< Meaning in value namespace.
-
-    // For error reporting
-    // FIXME (#3783): Merge me into TypeNsDef and ValueNsDef.
-    type_span: Option<span>,
-    value_span: Option<span>,
 }
 
 pub impl NameBindings {
@@ -548,18 +499,19 @@ pub impl NameBindings {
                 self.type_def = Some(TypeNsDef {
                     privacy: privacy,
                     module_def: Some(module_),
-                    type_def: None
+                    type_def: None,
+                    type_span: Some(sp)
                 });
             }
             Some(copy type_def) => {
                 self.type_def = Some(TypeNsDef {
                     privacy: privacy,
                     module_def: Some(module_),
+                    type_span: Some(sp),
                     .. type_def
                 });
             }
         }
-        self.type_span = Some(sp);
     }
 
     /// Records a type definition.
@@ -570,24 +522,24 @@ pub impl NameBindings {
                 self.type_def = Some(TypeNsDef {
                     privacy: privacy,
                     module_def: None,
-                    type_def: Some(def)
+                    type_def: Some(def),
+                    type_span: Some(sp)
                 });
             }
             Some(copy type_def) => {
                 self.type_def = Some(TypeNsDef {
                     privacy: privacy,
                     type_def: Some(def),
+                    type_span: Some(sp),
                     .. type_def
                 });
             }
         }
-        self.type_span = Some(sp);
     }
 
     /// Records a value definition.
     fn define_value(@mut self, privacy: Privacy, def: def, sp: span) {
-        self.value_def = Some(ValueNsDef { privacy: privacy, def: def });
-        self.value_span = Some(sp);
+        self.value_def = Some(ValueNsDef { privacy: privacy, def: def, value_span: Some(sp) });
     }
 
     /// Returns the module node if applicable.
@@ -686,8 +638,18 @@ pub impl NameBindings {
     fn span_for_namespace(&self, namespace: Namespace) -> Option<span> {
         if self.defined_in_namespace(namespace) {
             match namespace {
-                TypeNS  => self.type_span,
-                ValueNS => self.value_span,
+                TypeNS  => {
+                    match self.type_def {
+                        None => None,
+                        Some(type_def) => type_def.type_span
+                    }
+                }
+                ValueNS => {
+                    match self.value_def {
+                        None => None,
+                        Some(value_def) => value_def.value_span
+                    }
+                }
             }
         } else {
             None
@@ -698,9 +660,7 @@ pub impl NameBindings {
 pub fn NameBindings() -> NameBindings {
     NameBindings {
         type_def: None,
-        value_def: None,
-        type_span: None,
-        value_span: None
+        value_def: None
     }
 }
 
@@ -798,6 +758,7 @@ pub fn Resolver(session: Session,
         def_map: @mut HashMap::new(),
         export_map2: @mut HashMap::new(),
         trait_map: HashMap::new(),
+        used_imports: HashSet::new(),
 
         intr: session.intr()
     };
@@ -855,6 +816,8 @@ pub struct Resolver {
     def_map: DefMap,
     export_map2: ExportMap2,
     trait_map: TraitMap,
+
+    used_imports: HashSet<node_id>,
 }
 
 pub impl Resolver {
@@ -872,7 +835,7 @@ pub impl Resolver {
         self.resolve_crate();
         self.session.abort_if_errors();
 
-        self.check_for_unused_imports_if_necessary();
+        self.check_for_unused_imports();
     }
 
     //
@@ -1417,7 +1380,7 @@ pub impl Resolver {
                     // Build up the import directives.
                     let module_ = self.get_module_from_parent(parent);
                     match view_path.node {
-                        view_path_simple(binding, full_path, _) => {
+                        view_path_simple(binding, full_path, id) => {
                             let source_ident = *full_path.idents.last();
                             let subclass = @SingleImport(binding,
                                                          source_ident);
@@ -1425,7 +1388,8 @@ pub impl Resolver {
                                                         module_,
                                                         module_path,
                                                         subclass,
-                                                        view_path.span);
+                                                        view_path.span,
+                                                        id);
                         }
                         view_path_list(_, ref source_idents, _) => {
                             for source_idents.each |source_ident| {
@@ -1435,15 +1399,17 @@ pub impl Resolver {
                                                             module_,
                                                             copy module_path,
                                                             subclass,
-                                                            source_ident.span);
+                                                            source_ident.span,
+                                                            source_ident.node.id);
                             }
                         }
-                        view_path_glob(_, _) => {
+                        view_path_glob(_, id) => {
                             self.build_import_directive(privacy,
                                                         module_,
                                                         module_path,
                                                         @GlobImport,
-                                                        view_path.span);
+                                                        view_path.span,
+                                                        id);
                         }
                     }
                 }
@@ -1568,10 +1534,7 @@ pub impl Resolver {
                     // avoid creating cycles in the
                     // module graph.
 
-                    let resolution =
-                        @mut ImportResolution(Public,
-                                              dummy_sp(),
-                                              @mut ImportState());
+                    let resolution = @mut ImportResolution(Public, 0);
                     resolution.outstanding_references = 0;
 
                     match existing_module.parent_link {
@@ -1833,9 +1796,10 @@ pub impl Resolver {
                               module_: @mut Module,
                               module_path: ~[ident],
                               subclass: @ImportDirectiveSubclass,
-                              span: span) {
+                              span: span,
+                              id: node_id) {
         let directive = @ImportDirective(privacy, module_path,
-                                         subclass, span);
+                                         subclass, span, id);
         module_.imports.push(directive);
 
         // Bump the reference count on the name. Or, if this is a glob, set
@@ -1857,16 +1821,7 @@ pub impl Resolver {
                     }
                     None => {
                         debug!("(building import directive) creating new");
-                        let state = @mut ImportState();
-                        let resolution = @mut ImportResolution(privacy,
-                                                               span,
-                                                               state);
-                        let name = self.idents_to_str(directive.module_path);
-                        // Don't warn about unused intrinsics because they're
-                        // automatically appended to all files
-                        if name == ~"intrinsic::rusti" {
-                            resolution.state.warned = true;
-                        }
+                        let resolution = @mut ImportResolution(privacy, id);
                         resolution.outstanding_references = 1;
                         module_.import_resolutions.insert(target, resolution);
                     }
@@ -2062,13 +2017,12 @@ pub impl Resolver {
                                                        import_directive.span);
                     }
                     GlobImport => {
-                        let span = import_directive.span;
                         let privacy = import_directive.privacy;
                         resolution_result =
                             self.resolve_glob_import(privacy,
                                                      module_,
                                                      containing_module,
-                                                     span);
+                                                     import_directive.id);
                     }
                 }
             }
@@ -2111,10 +2065,9 @@ pub impl Resolver {
                 privacy: Public,
                 module_def: Some(module),
                 type_def: None,
+                type_span: None
             }),
             value_def: None,
-            type_span: None,
-            value_span: None,
         }
     }
 
@@ -2196,7 +2149,8 @@ pub impl Resolver {
                             if import_resolution.outstanding_references
                                 == 0 => {
 
-                        fn get_binding(import_resolution:
+                        fn get_binding(this: @mut Resolver,
+                                       import_resolution:
                                           @mut ImportResolution,
                                        namespace: Namespace)
                                     -> NamespaceResult {
@@ -2213,7 +2167,7 @@ pub impl Resolver {
                                     return UnboundResult;
                                 }
                                 Some(target) => {
-                                    import_resolution.state.used = true;
+                                    this.used_imports.insert(import_resolution.id);
                                     return BoundResult(target.target_module,
                                                     target.bindings);
                                 }
@@ -2223,11 +2177,11 @@ pub impl Resolver {
                         // The name is an import which has been fully
                         // resolved. We can, therefore, just follow it.
                         if value_result.is_unknown() {
-                            value_result = get_binding(*import_resolution,
+                            value_result = get_binding(self, *import_resolution,
                                                        ValueNS);
                         }
                         if type_result.is_unknown() {
-                            type_result = get_binding(*import_resolution,
+                            type_result = get_binding(self, *import_resolution,
                                                       TypeNS);
                         }
                     }
@@ -2352,13 +2306,12 @@ pub impl Resolver {
                            privacy: Privacy,
                            module_: @mut Module,
                            containing_module: @mut Module,
-                           span: span)
+                           id: node_id)
                         -> ResolveResult<()> {
         // This function works in a highly imperative manner; it eagerly adds
         // everything it can to the list of import resolutions of the module
         // node.
         debug!("(resolving glob import) resolving %? glob import", privacy);
-        let state = @mut ImportState();
 
         // We must bail out if the node has unresolved imports of any kind
         // (including globs).
@@ -2384,9 +2337,7 @@ pub impl Resolver {
                 None if target_import_resolution.privacy == Public => {
                     // Simple: just copy the old import resolution.
                     let new_import_resolution =
-                        @mut ImportResolution(privacy,
-                                              target_import_resolution.span,
-                                              state);
+                        @mut ImportResolution(privacy, id);
                     new_import_resolution.value_target =
                         copy target_import_resolution.value_target;
                     new_import_resolution.type_target =
@@ -2428,9 +2379,7 @@ pub impl Resolver {
             match module_.import_resolutions.find(&ident) {
                 None => {
                     // Create a new import resolution from this child.
-                    dest_import_resolution = @mut ImportResolution(privacy,
-                                                                   span,
-                                                                   state);
+                    dest_import_resolution = @mut ImportResolution(privacy, id);
                     module_.import_resolutions.insert
                         (ident, dest_import_resolution);
                 }
@@ -2708,7 +2657,7 @@ pub impl Resolver {
                     Some(target) => {
                         debug!("(resolving item in lexical scope) using \
                                 import resolution");
-                        import_resolution.state.used = true;
+                        self.used_imports.insert(import_resolution.id);
                         return Success(copy target);
                     }
                 }
@@ -2979,7 +2928,7 @@ pub impl Resolver {
                             import_resolution.privacy == Public => {
                         debug!("(resolving name in module) resolved to \
                                 import");
-                        import_resolution.state.used = true;
+                        self.used_imports.insert(import_resolution.id);
                         return Success(copy target);
                     }
                     Some(_) => {
@@ -3727,17 +3676,23 @@ pub impl Resolver {
                                type_parameters: &OptVec<TyParam>,
                                visitor: ResolveVisitor) {
         for type_parameters.each |type_parameter| {
-            for type_parameter.bounds.each |&bound| {
-                match bound {
-                    TraitTyParamBound(tref) => {
-                        self.resolve_trait_reference(tref, visitor)
-                    }
-                    RegionTyParamBound => {}
-                }
+            for type_parameter.bounds.each |bound| {
+                self.resolve_type_parameter_bound(bound, visitor);
             }
         }
     }
 
+    fn resolve_type_parameter_bound(@mut self,
+                                    type_parameter_bound: &TyParamBound,
+                                    visitor: ResolveVisitor) {
+        match *type_parameter_bound {
+            TraitTyParamBound(tref) => {
+                self.resolve_trait_reference(tref, visitor)
+            }
+            RegionTyParamBound => {}
+        }
+    }
+
     fn resolve_trait_reference(@mut self,
                                trait_reference: &trait_ref,
                                visitor: ResolveVisitor) {
@@ -4065,6 +4020,13 @@ pub impl Resolver {
                 }
             }
 
+            ty_closure(c) => {
+                for c.bounds.each |bound| {
+                    self.resolve_type_parameter_bound(bound, visitor);
+                }
+                visit_ty(ty, (), visitor);
+            }
+
             _ => {
                 // Just resolve embedded types.
                 visit_ty(ty, (), visitor);
@@ -4447,7 +4409,7 @@ pub impl Resolver {
                                     namespace)) {
                             (Some(def), Some(Public)) => {
                                 // Found it.
-                                import_resolution.state.used = true;
+                                self.used_imports.insert(import_resolution.id);
                                 return ImportNameDefinition(def);
                             }
                             (Some(_), _) | (None, _) => {
@@ -5027,8 +4989,8 @@ pub impl Resolver {
                                             &mut found_traits,
                                             trait_def_id, name);
                                         if added {
-                                            import_resolution.state.used =
-                                                true;
+                                            self.used_imports.insert(
+                                                import_resolution.id);
                                         }
                                     }
                                     _ => {
@@ -5126,86 +5088,50 @@ pub impl Resolver {
     // resolve data structures.
     //
 
-    fn unused_import_lint_level(@mut self, m: @mut Module) -> level {
-        let settings = self.session.lint_settings;
-        match m.def_id {
-            Some(def) => get_lint_settings_level(settings, unused_imports,
-                                                 def.node, def.node),
-            None => get_lint_level(settings.default_settings, unused_imports)
-        }
-    }
-
-    fn check_for_unused_imports_if_necessary(@mut self) {
-        if self.unused_import_lint_level(self.current_module) == allow {
-            return;
-        }
-
-        let root_module = self.graph_root.get_module();
-        self.check_for_unused_imports_in_module_subtree(root_module);
+    fn check_for_unused_imports(@mut self) {
+        let vt = mk_simple_visitor(@SimpleVisitor {
+            visit_view_item: |vi| self.check_for_item_unused_imports(vi),
+            .. *default_simple_visitor()
+        });
+        visit_crate(self.crate, (), vt);
     }
 
-    fn check_for_unused_imports_in_module_subtree(@mut self,
-                                                  module_: @mut Module) {
-        // If this isn't a local crate, then bail out. We don't need to check
-        // for unused imports in external crates.
-
-        match module_.def_id {
-            Some(def_id) if def_id.crate == local_crate => {
-                // OK. Continue.
-            }
-            None => {
-                // Check for unused imports in the root module.
-            }
-            Some(_) => {
-                // Bail out.
-                debug!("(checking for unused imports in module subtree) not \
-                        checking for unused imports for `%s`",
-                       self.module_to_str(module_));
-                return;
-            }
-        }
-
-        self.check_for_unused_imports_in_module(module_);
+    fn check_for_item_unused_imports(&mut self, vi: @view_item) {
+        // Ignore public import statements because there's no way to be sure
+        // whether they're used or not. Also ignore imports with a dummy span
+        // because this means that they were generated in some fashion by the
+        // compiler and we don't need to consider them.
+        if vi.vis == public { return }
+        if vi.span == dummy_sp() { return }
+
+        match vi.node {
+            view_item_extern_mod(*) => {} // ignore
+            view_item_use(ref path) => {
+                for path.each |p| {
+                    match p.node {
+                        view_path_simple(_, _, id) | view_path_glob(_, id) => {
+                            if !self.used_imports.contains(&id) {
+                                self.session.add_lint(unused_imports,
+                                                      id, vi.span,
+                                                      ~"unused import");
+                            }
+                        }
 
-        for module_.children.each_value |&child_name_bindings| {
-            match (*child_name_bindings).get_module_if_available() {
-                None => {
-                    // Nothing to do.
-                }
-                Some(child_module) => {
-                    self.check_for_unused_imports_in_module_subtree
-                        (child_module);
+                        view_path_list(_, ref list, _) => {
+                            for list.each |i| {
+                                if !self.used_imports.contains(&i.node.id) {
+                                    self.session.add_lint(unused_imports,
+                                                          i.node.id, i.span,
+                                                          ~"unused import");
+                                }
+                            }
+                        }
+                    }
                 }
             }
         }
-
-        for module_.anonymous_children.each_value |&child_module| {
-            self.check_for_unused_imports_in_module_subtree(child_module);
-        }
-    }
-
-    fn check_for_unused_imports_in_module(@mut self, module_: @mut Module) {
-        for module_.import_resolutions.each_value |&import_resolution| {
-            // Ignore dummy spans for things like automatically injected
-            // imports for the prelude, and also don't warn about the same
-            // import statement being unused more than once. Furthermore, if
-            // the import is public, then we can't be sure whether it's unused
-            // or not so don't warn about it.
-            if !import_resolution.state.used &&
-                    !import_resolution.state.warned &&
-                    import_resolution.span != dummy_sp() &&
-                    import_resolution.privacy != Public {
-                import_resolution.state.warned = true;
-                let span = import_resolution.span;
-                self.session.span_lint_level(
-                    self.unused_import_lint_level(module_),
-                    span,
-                    ~"unused import");
-            }
-        }
     }
 
-
     //
     // Diagnostics
     //
diff --git a/src/librustc/middle/resolve_stage0.rs b/src/librustc/middle/resolve_stage0.rs
index a404dcf7249..713132b12fc 100644
--- a/src/librustc/middle/resolve_stage0.rs
+++ b/src/librustc/middle/resolve_stage0.rs
@@ -17,8 +17,7 @@ use metadata::csearch::get_type_name_if_impl;
 use metadata::cstore::find_extern_mod_stmt_cnum;
 use metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
 use middle::lang_items::LanguageItems;
-use middle::lint::{allow, level, unused_imports};
-use middle::lint::{get_lint_level, get_lint_settings_level};
+use middle::lint::{allow, level, warn};
 use middle::pat_util::pat_bindings;
 
 use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm};
@@ -5168,14 +5167,7 @@ pub impl Resolver {
     // resolve data structures.
     //
 
-    fn unused_import_lint_level(@mut self, m: @mut Module) -> level {
-        let settings = self.session.lint_settings;
-        match m.def_id {
-            Some(def) => get_lint_settings_level(settings, unused_imports,
-                                                 def.node, def.node),
-            None => get_lint_level(settings.default_settings, unused_imports)
-        }
-    }
+    fn unused_import_lint_level(@mut self, _: @mut Module) -> level { warn }
 
     fn check_for_unused_imports_if_necessary(@mut self) {
         if self.unused_import_lint_level(self.current_module) == allow {
@@ -5237,12 +5229,7 @@ pub impl Resolver {
                     !import_resolution.state.warned &&
                     import_resolution.span != dummy_sp() &&
                     import_resolution.privacy != Public {
-                import_resolution.state.warned = true;
-                let span = import_resolution.span;
-                self.session.span_lint_level(
-                    self.unused_import_lint_level(module_),
-                    span,
-                    ~"unused import");
+                // I swear I work in not(stage0)!
             }
         }
     }
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index e14d6d79ab5..b5cca20d8ec 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -2228,8 +2228,7 @@ pub fn register_fn_fuller(ccx: @CrateContext,
         mangle_exported_name(ccx, /*bad*/copy path, node_type)
     };
 
-    // XXX: Bad copy.
-    let llfn: ValueRef = decl_fn(ccx.llmod, copy ps, cc, llfty);
+    let llfn: ValueRef = decl_fn(ccx.llmod, ps, cc, llfty);
     ccx.item_symbols.insert(node_id, ps);
 
     // FIXME #4404 android JNI hacks
diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs
index 7f1f35b33ab..e8853fd20e9 100644
--- a/src/librustc/middle/trans/build.rs
+++ b/src/librustc/middle/trans/build.rs
@@ -544,7 +544,7 @@ pub fn AtomicLoad(cx: block, PointerVal: ValueRef, order: AtomicOrdering) -> Val
             return llvm::LLVMGetUndef(ccx.int_type);
         }
         count_insn(cx, "load.atomic");
-        return llvm::LLVMBuildAtomicLoad(B(cx), PointerVal, order);
+        return llvm::LLVMBuildAtomicLoad(B(cx), PointerVal, noname(), order);
     }
 }
 
diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs
index 374bb23f2cb..8055d919ffd 100644
--- a/src/librustc/middle/trans/datum.rs
+++ b/src/librustc/middle/trans/datum.rs
@@ -101,7 +101,6 @@ use middle::ty;
 use util::common::indenter;
 use util::ppaux::ty_to_str;
 
-use core::container::Set; // XXX: this should not be necessary
 use core::to_bytes;
 use syntax::ast;
 use syntax::codemap::span;
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 5b1cae473f7..fd545ca2c6e 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -818,6 +818,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
                 sigil: ast::BorrowedSigil,
                 onceness: ast::Many,
                 region: ty::re_bound(ty::br_anon(0)),
+                bounds: ty::EmptyBuiltinBounds(),
                 sig: FnSig {
                     bound_lifetime_names: opt_vec::Empty,
                     inputs: ~[ star_u8 ],
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index bdbb45bf275..6eb2540f1df 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -795,8 +795,11 @@ pub fn make_impl_vtable(ccx: @CrateContext,
     let _icx = ccx.insn_ctxt("impl::make_impl_vtable");
     let tcx = ccx.tcx;
 
-    // XXX: This should support multiple traits.
-    let trt_id = ty::impl_trait_refs(tcx, impl_id)[0].def_id;
+    let trt_id = match ty::impl_trait_ref(tcx, impl_id) {
+        Some(t_id) => t_id.def_id,
+        None       => ccx.sess.bug("make_impl_vtable: don't know how to \
+                                    make a vtable for a type impl!")
+    };
 
     let has_tps =
         !ty::lookup_item_type(ccx.tcx, impl_id).generics.type_param_defs.is_empty();
diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs
index 3b0c03cdc99..ccc906f2ee8 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -330,6 +330,7 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt,
                 sigil: sigil,
                 onceness: ast::Many,
                 region: ty::re_static,
+                bounds: ty::EmptyBuiltinBounds(),
                 sig: ty::FnSig {bound_lifetime_names: opt_vec::Empty,
                                 inputs: ~[],
                                 output: ty::mk_nil()}})
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 4ee2c5b0100..c51fba8a62b 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -22,7 +22,7 @@ use middle::typeck;
 use middle;
 use util::ppaux::{note_and_explain_region, bound_region_to_str};
 use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str};
-use util::ppaux::Repr;
+use util::ppaux::{Repr, UserString};
 use util::common::{indenter};
 use util::enum_set::{EnumSet, CLike};
 
@@ -96,9 +96,7 @@ pub struct mt {
     mutbl: ast::mutability,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum vstore {
     vstore_fixed(uint),
     vstore_uniq,
@@ -106,9 +104,7 @@ pub enum vstore {
     vstore_slice(Region)
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq, IterBytes)]
+#[deriving(Eq, IterBytes, Encodable, Decodable)]
 pub enum TraitStore {
     BoxTraitStore,              // @Trait
     UniqTraitStore,             // ~Trait
@@ -117,9 +113,7 @@ pub enum TraitStore {
 
 // XXX: This should probably go away at some point. Maybe after destructors
 // do?
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum SelfMode {
     ByCopy,
     ByRef,
@@ -197,27 +191,22 @@ pub enum ast_ty_to_ty_cache_entry {
 
 pub type opt_region_variance = Option<region_variance>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Decodable, Encodable)]
 pub enum region_variance { rv_covariant, rv_invariant, rv_contravariant }
 
-#[auto_encode]
-#[auto_decode]
+#[deriving(Decodable, Encodable)]
 pub enum AutoAdjustment {
     AutoAddEnv(ty::Region, ast::Sigil),
     AutoDerefRef(AutoDerefRef)
 }
 
-#[auto_encode]
-#[auto_decode]
+#[deriving(Decodable, Encodable)]
 pub struct AutoDerefRef {
     autoderefs: uint,
     autoref: Option<AutoRef>
 }
 
-#[auto_encode]
-#[auto_decode]
+#[deriving(Decodable, Encodable)]
 pub enum AutoRef {
     /// Convert from T to &T
     AutoPtr(Region, ast::mutability),
@@ -401,7 +390,8 @@ pub struct ClosureTy {
     sigil: ast::Sigil,
     onceness: ast::Onceness,
     region: Region,
-    sig: FnSig
+    bounds: BuiltinBounds,
+    sig: FnSig,
 }
 
 /**
@@ -453,9 +443,7 @@ pub struct param_ty {
 }
 
 /// Representation of regions:
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq, IterBytes)]
+#[deriving(Eq, IterBytes, Encodable, Decodable)]
 pub enum Region {
     /// Bound regions are found (primarily) in function types.  They indicate
     /// region parameters that have yet to be replaced with actual regions
@@ -501,17 +489,13 @@ pub impl Region {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq, IterBytes)]
+#[deriving(Eq, IterBytes, Encodable, Decodable)]
 pub struct FreeRegion {
     scope_id: node_id,
     bound_region: bound_region
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq, IterBytes)]
+#[deriving(Eq, IterBytes, Encodable, Decodable)]
 pub enum bound_region {
     /// The self region for structs, impls (&T in a type defn or &'self T)
     br_self,
@@ -702,6 +686,7 @@ pub enum type_err {
     terr_int_mismatch(expected_found<IntVarValue>),
     terr_float_mismatch(expected_found<ast::float_ty>),
     terr_traits(expected_found<ast::def_id>),
+    terr_builtin_bounds(expected_found<BuiltinBounds>),
 }
 
 #[deriving(Eq, IterBytes)]
@@ -724,6 +709,15 @@ pub fn EmptyBuiltinBounds() -> BuiltinBounds {
     EnumSet::empty()
 }
 
+pub fn AllBuiltinBounds() -> BuiltinBounds {
+    let mut set = EnumSet::empty();
+    set.add(BoundCopy);
+    set.add(BoundStatic);
+    set.add(BoundOwned);
+    set.add(BoundConst);
+    set
+}
+
 impl CLike for BuiltinBound {
     pub fn to_uint(&self) -> uint {
         *self as uint
@@ -742,9 +736,7 @@ pub struct IntVid(uint);
 #[deriving(Eq)]
 pub struct FloatVid(uint);
 
-#[deriving(Eq)]
-#[auto_encode]
-#[auto_decode]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct RegionVid {
     id: uint
 }
@@ -777,8 +769,7 @@ impl to_bytes::IterBytes for InferTy {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
+#[deriving(Encodable, Decodable)]
 pub enum InferRegion {
     ReVar(RegionVid),
     ReSkolemized(uint, bound_region)
@@ -3189,6 +3180,7 @@ pub fn adjust_ty(cx: ctxt,
                                        sigil: s,
                                        onceness: ast::Many,
                                        region: r,
+                                       bounds: ty::AllBuiltinBounds(),
                                        sig: copy b.sig})
                 }
                 ref b => {
@@ -3717,6 +3709,19 @@ pub fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
                  item_path_str(cx, values.expected),
                  item_path_str(cx, values.found))
         }
+        terr_builtin_bounds(values) => {
+            if values.expected.is_empty() {
+                fmt!("expected no bounds but found `%s`",
+                     values.found.user_string(cx))
+            } else if values.found.is_empty() {
+                fmt!("expected bounds `%s` but found no bounds",
+                     values.expected.user_string(cx))
+            } else {
+                fmt!("expected bounds `%s` but found bounds `%s`",
+                     values.expected.user_string(cx),
+                     values.found.user_string(cx))
+            }
+        }
         terr_self_substs => {
             ~"inconsistent self substitution" // XXX this is more of a bug
         }
@@ -3878,23 +3883,23 @@ pub fn trait_method_def_ids(cx: ctxt, id: ast::def_id) -> @~[def_id] {
         || @csearch::get_trait_method_def_ids(cx.cstore, id))
 }
 
-pub fn impl_trait_refs(cx: ctxt, id: ast::def_id) -> ~[@TraitRef] {
+pub fn impl_trait_ref(cx: ctxt, id: ast::def_id) -> Option<@TraitRef> {
     if id.crate == ast::local_crate {
-        debug!("(impl_traits) searching for trait impl %?", id);
+        debug!("(impl_trait_ref) searching for trait impl %?", id);
         match cx.items.find(&id.node) {
            Some(&ast_map::node_item(@ast::item {
                         node: ast::item_impl(_, opt_trait, _, _),
                         _},
                     _)) => {
                match opt_trait {
-                   Some(t) => ~[ty::node_id_to_trait_ref(cx, t.ref_id)],
-                   None => ~[]
+                   Some(t) => Some(ty::node_id_to_trait_ref(cx, t.ref_id)),
+                   None => None
                }
            }
-           _ => ~[]
+           _ => None
         }
     } else {
-        csearch::get_impl_traits(cx, id)
+        csearch::get_impl_trait(cx, id)
     }
 }
 
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index de6064b0a31..222493b0564 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -59,6 +59,7 @@ use middle::ty;
 use middle::typeck::rscope::in_binding_rscope;
 use middle::typeck::rscope::{region_scope, RegionError};
 use middle::typeck::rscope::RegionParamNames;
+use middle::typeck::lookup_def_tcx;
 
 use syntax::abi::AbiSet;
 use syntax::{ast, ast_util};
@@ -220,7 +221,6 @@ pub fn ast_path_to_trait_ref<AC:AstConv,RS:region_scope + Copy + 'static>(
     return trait_ref;
 }
 
-
 pub fn ast_path_to_ty<AC:AstConv,RS:region_scope + Copy + 'static>(
         this: &AC,
         rscope: &RS,
@@ -377,11 +377,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
                                             bf.abis, &bf.lifetimes, &bf.decl))
       }
       ast::ty_closure(ref f) => {
+          let bounds = conv_builtin_bounds(this.tcx(), &f.bounds);
           let fn_decl = ty_of_closure(this,
                                       rscope,
                                       f.sigil,
                                       f.purity,
                                       f.onceness,
+                                      bounds,
                                       f.region,
                                       &f.decl,
                                       None,
@@ -646,17 +648,18 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:region_scope + Copy + 'static>(
 }
 
 pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>(
-        this: &AC,
-        rscope: &RS,
-        sigil: ast::Sigil,
-        purity: ast::purity,
-        onceness: ast::Onceness,
-        opt_lifetime: Option<@ast::Lifetime>,
-        decl: &ast::fn_decl,
-        expected_sig: Option<ty::FnSig>,
-        lifetimes: &OptVec<ast::Lifetime>,
-        span: span)
-     -> ty::ClosureTy
+    this: &AC,
+    rscope: &RS,
+    sigil: ast::Sigil,
+    purity: ast::purity,
+    onceness: ast::Onceness,
+    bounds: ty::BuiltinBounds,
+    opt_lifetime: Option<@ast::Lifetime>,
+    decl: &ast::fn_decl,
+    expected_sig: Option<ty::FnSig>,
+    lifetimes: &OptVec<ast::Lifetime>,
+    span: span)
+    -> ty::ClosureTy
 {
     // The caller should not both provide explicit bound lifetime
     // names and expected types.  Either we infer the bound lifetime
@@ -713,8 +716,69 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>(
         sigil: sigil,
         onceness: onceness,
         region: bound_region,
+        bounds: bounds,
         sig: ty::FnSig {bound_lifetime_names: bound_lifetime_names,
                         inputs: input_tys,
                         output: output_ty}
     }
 }
+
+fn conv_builtin_bounds(tcx: ty::ctxt,
+                       ast_bounds: &OptVec<ast::TyParamBound>)
+                       -> ty::BuiltinBounds {
+    //! Converts a list of bounds from the AST into a `BuiltinBounds`
+    //! struct. Reports an error if any of the bounds that appear
+    //! in the AST refer to general traits and not the built-in traits
+    //! like `Copy` or `Owned`. Used to translate the bounds that
+    //! appear in closure and trait types, where only builtin bounds are
+    //! legal.
+
+    let mut builtin_bounds = ty::EmptyBuiltinBounds();
+    for ast_bounds.each |ast_bound| {
+        match *ast_bound {
+            ast::TraitTyParamBound(b) => {
+                match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
+                    ast::def_trait(trait_did) => {
+                        if try_add_builtin_trait(tcx,
+                                                 trait_did,
+                                                 &mut builtin_bounds) {
+                            loop; // success
+                        }
+                    }
+                    _ => { }
+                }
+                tcx.sess.span_fatal(
+                    b.path.span,
+                    fmt!("only the builtin traits can be used \
+                          as closure or object bounds"));
+            }
+            ast::RegionTyParamBound => {
+                builtin_bounds.add(ty::BoundStatic);
+            }
+        }
+    }
+    builtin_bounds
+}
+
+pub fn try_add_builtin_trait(tcx: ty::ctxt,
+                             trait_def_id: ast::def_id,
+                             builtin_bounds: &mut ty::BuiltinBounds) -> bool {
+    //! Checks whether `trait_ref` refers to one of the builtin
+    //! traits, like `Copy` or `Owned`, and adds the corresponding
+    //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
+    //! is a builtin trait.
+
+    let li = &tcx.lang_items;
+    if trait_def_id == li.owned_trait() {
+        builtin_bounds.add(ty::BoundOwned);
+        true
+    } else if trait_def_id == li.copy_trait() {
+        builtin_bounds.add(ty::BoundCopy);
+        true
+    } else if trait_def_id == li.const_trait() {
+        builtin_bounds.add(ty::BoundConst);
+        true
+    } else {
+        false
+    }
+}
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 548b9e454ce..8d32bb7f677 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -1661,7 +1661,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
         let (expected_sig,
              expected_purity,
              expected_sigil,
-             expected_onceness) = {
+             expected_onceness,
+             expected_bounds) = {
             match expected_sty {
                 Some(ty::ty_closure(ref cenv)) => {
                     let id = expr.id;
@@ -1669,11 +1670,13 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
                         replace_bound_regions_in_fn_sig(
                             tcx, @Nil, None, &cenv.sig,
                             |br| ty::re_bound(ty::br_cap_avoid(id, @br)));
-                    (Some(sig), cenv.purity, cenv.sigil, cenv.onceness)
+                    (Some(sig), cenv.purity, cenv.sigil,
+                     cenv.onceness, cenv.bounds)
                 }
                 _ => {
                     // Not an error! Means we're inferring the closure type
-                    (None, ast::impure_fn, ast::BorrowedSigil, ast::Many)
+                    (None, ast::impure_fn, ast::BorrowedSigil,
+                     ast::Many, ty::EmptyBuiltinBounds())
                 }
             }
         };
@@ -1687,15 +1690,16 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
 
         // construct the function type
         let fn_ty = astconv::ty_of_closure(fcx,
-                                               fcx,
-                                               sigil,
-                                               purity,
-                                               expected_onceness,
-                                               None,
-                                               decl,
-                                               expected_sig,
-                                               &opt_vec::Empty,
-                                               expr.span);
+                                           fcx,
+                                           sigil,
+                                           purity,
+                                           expected_onceness,
+                                           expected_bounds,
+                                           None,
+                                           decl,
+                                           expected_sig,
+                                           &opt_vec::Empty,
+                                           expr.span);
 
         let fty_sig;
         let fty = if error_happened {
@@ -3526,6 +3530,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
             sigil: ast::BorrowedSigil,
             onceness: ast::Once,
             region: ty::re_bound(ty::br_anon(0)),
+            bounds: ty::EmptyBuiltinBounds(),
             sig: ty::FnSig {
                 bound_lifetime_names: opt_vec::Empty,
                 inputs: ~[ty::mk_imm_ptr(ccx.tcx, ty::mk_mach_uint(ast::ty_u8))],
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index 42ab9d97729..2e2b4550f63 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -261,24 +261,14 @@ fn lookup_vtable(vcx: &VtableContext,
                         }
                         impls_seen.insert(im.did);
 
-                        // ty::impl_traits gives us the list of all
-                        // traits that im implements. Again, usually
-                        // there's just one.
+                        // ty::impl_traits gives us the trait im implements,
+                        // if there is one (there's either zero or one).
                         //
-                        // For example, if im represented the struct
-                        // in:
-                        //
-                        //   struct foo : baz<int>, bar, quux { ... }
-                        //
-                        // then ty::impl_traits would return
-                        //
-                        //   ~[baz<int>, bar, quux]
-                        //
-                        // For each of the traits foo implements, if
-                        // it's the same trait as trait_ref, we need to
+                        // If foo implements a trait t, and if t is the
+                        // same trait as trait_ref, we need to
                         // unify it with trait_ref in order to get all
                         // the ty vars sorted out.
-                        for ty::impl_trait_refs(tcx, im.did).each |&of_trait_ref|
+                        for ty::impl_trait_ref(tcx, im.did).each |&of_trait_ref|
                         {
                             if of_trait_ref.def_id != trait_ref.def_id { loop; }
 
@@ -456,8 +446,12 @@ fn connect_trait_tps(vcx: &VtableContext,
 {
     let tcx = vcx.tcx();
 
-    // XXX: This should work for multiple traits.
-    let impl_trait_ref = ty::impl_trait_refs(tcx, impl_did)[0];
+    let impl_trait_ref = match ty::impl_trait_ref(tcx, impl_did) {
+        Some(t) => t,
+        None => vcx.tcx().sess.span_bug(location_info.span,
+                                  "connect_trait_tps invoked on a type impl")
+    };
+
     let impl_trait_ref = (*impl_trait_ref).subst(tcx, impl_substs);
     relate_trait_refs(vcx, location_info, &impl_trait_ref, trait_ref);
 }
diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
index c64a0235eb1..311aa551601 100644
--- a/src/librustc/middle/typeck/coherence.rs
+++ b/src/librustc/middle/typeck/coherence.rs
@@ -16,7 +16,7 @@
 
 
 use driver;
-use metadata::csearch::{each_path, get_impl_traits};
+use metadata::csearch::{each_path, get_impl_trait};
 use metadata::csearch::{get_impls_for_mod};
 use metadata::csearch;
 use metadata::cstore::{CStore, iter_crate_data};
@@ -898,13 +898,13 @@ pub impl CoherenceChecker {
 
             let self_type = lookup_item_type(self.crate_context.tcx,
                                              implementation.did);
-            let associated_traits = get_impl_traits(self.crate_context.tcx,
+            let associated_traits = get_impl_trait(self.crate_context.tcx,
                                                     implementation.did);
 
             // Do a sanity check to make sure that inherent methods have base
             // types.
 
-            if associated_traits.len() == 0 {
+            if associated_traits.is_none() {
                 match get_base_type_def_id(self.inference_context,
                                            dummy_sp(),
                                            self_type.ty) {
@@ -940,7 +940,7 @@ pub impl CoherenceChecker {
                 Some(base_type_def_id) => {
                     // inherent methods apply to `impl Type` but not
                     // `impl Trait for Type`:
-                    if associated_traits.len() == 0 {
+                    if associated_traits.is_none() {
                         self.add_inherent_method(base_type_def_id,
                                                  *implementation);
                     }
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index 4773e637c35..6c7f73177fa 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -1207,25 +1207,21 @@ pub fn ty_generics(ccx: &CrateCtxt,
             builtin_bounds: ty::EmptyBuiltinBounds(),
             trait_bounds: ~[]
         };
-        for ast_bounds.each |b| {
-            match b {
-                &TraitTyParamBound(b) => {
-                    let li = &ccx.tcx.lang_items;
+        for ast_bounds.each |ast_bound| {
+            match *ast_bound {
+                TraitTyParamBound(b) => {
                     let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id);
                     let trait_ref = instantiate_trait_ref(ccx, b, rp, generics, ty);
-                    if trait_ref.def_id == li.owned_trait() {
-                        param_bounds.builtin_bounds.add(ty::BoundOwned);
-                    } else if trait_ref.def_id == li.copy_trait() {
-                        param_bounds.builtin_bounds.add(ty::BoundCopy);
-                    } else if trait_ref.def_id == li.const_trait() {
-                        param_bounds.builtin_bounds.add(ty::BoundConst);
-                    } else {
+                    if !astconv::try_add_builtin_trait(
+                        ccx.tcx, trait_ref.def_id,
+                        &mut param_bounds.builtin_bounds)
+                    {
                         // Must be a user-defined trait
                         param_bounds.trait_bounds.push(trait_ref);
                     }
                 }
 
-                &RegionTyParamBound => {
+                RegionTyParamBound => {
                     param_bounds.builtin_bounds.add(ty::BoundStatic);
                 }
             }
diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs
index fcd2c6ffe59..3c337d17f86 100644
--- a/src/librustc/middle/typeck/infer/combine.rs
+++ b/src/librustc/middle/typeck/infer/combine.rs
@@ -56,6 +56,7 @@
 
 use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
 use middle::ty::{IntType, UintType, substs};
+use middle::ty::{BuiltinBounds};
 use middle::ty;
 use middle::typeck::infer::glb::Glb;
 use middle::typeck::infer::lub::Lub;
@@ -100,6 +101,7 @@ pub trait Combine {
     fn purities(&self, a: purity, b: purity) -> cres<purity>;
     fn abis(&self, a: AbiSet, b: AbiSet) -> cres<AbiSet>;
     fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness>;
+    fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds>;
     fn contraregions(&self, a: ty::Region, b: ty::Region)
                   -> cres<ty::Region>;
     fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region>;
@@ -372,11 +374,13 @@ pub fn super_closure_tys<C:Combine>(
     let r = if_ok!(this.contraregions(a_f.region, b_f.region));
     let purity = if_ok!(this.purities(a_f.purity, b_f.purity));
     let onceness = if_ok!(this.oncenesses(a_f.onceness, b_f.onceness));
+    let bounds = if_ok!(this.bounds(a_f.bounds, b_f.bounds));
     let sig = if_ok!(this.fn_sigs(&a_f.sig, &b_f.sig));
     Ok(ty::ClosureTy {purity: purity,
                       sigil: p,
                       onceness: onceness,
                       region: r,
+                      bounds: bounds,
                       sig: sig})
 }
 
diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs
index 42e42ddb1e7..9ade6de6cf4 100644
--- a/src/librustc/middle/typeck/infer/glb.rs
+++ b/src/librustc/middle/typeck/infer/glb.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use middle::ty::{BuiltinBounds};
 use middle::ty::RegionVid;
 use middle::ty;
 use middle::typeck::infer::combine::*;
@@ -114,6 +115,12 @@ impl Combine for Glb {
         }
     }
 
+    fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
+        // More bounds is a subtype of fewer bounds, so
+        // the GLB (mutual subtype) is the union.
+        Ok(a.union(b))
+    }
+
     fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
         debug!("%s.regions(%?, %?)",
                self.tag(),
diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs
index 20a051f0531..82fd4e3ae6d 100644
--- a/src/librustc/middle/typeck/infer/lub.rs
+++ b/src/librustc/middle/typeck/infer/lub.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use middle::ty::{BuiltinBounds};
 use middle::ty::RegionVid;
 use middle::ty;
 use middle::typeck::infer::combine::*;
@@ -100,6 +101,12 @@ impl Combine for Lub {
         }
     }
 
+    fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
+        // More bounds is a subtype of fewer bounds, so
+        // the LUB (mutual supertype) is the intersection.
+        Ok(a.intersection(b))
+    }
+
     fn contraregions(&self, a: ty::Region, b: ty::Region)
                     -> cres<ty::Region> {
         return Glb(**self).regions(a, b);
diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs
index ca083bc2d86..8da3d7bfa00 100644
--- a/src/librustc/middle/typeck/infer/sub.rs
+++ b/src/librustc/middle/typeck/infer/sub.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use middle::ty::{BuiltinBounds};
 use middle::ty;
 use middle::ty::TyVar;
 use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
@@ -99,6 +100,19 @@ impl Combine for Sub {
         })
     }
 
+    fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
+        // More bounds is a subtype of fewer bounds.
+        //
+        // e.g., fn:Copy() <: fn(), because the former is a function
+        // that only closes over copyable things, but the latter is
+        // any function at all.
+        if a.contains(b) {
+            Ok(a)
+        } else {
+            Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
+        }
+    }
+
     fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
         debug!("%s.tys(%s, %s)", self.tag(),
                a.inf_str(self.infcx), b.inf_str(self.infcx));
diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs
index 0dec0fc937b..dd313c54efb 100644
--- a/src/librustc/middle/typeck/mod.rs
+++ b/src/librustc/middle/typeck/mod.rs
@@ -73,8 +73,7 @@ pub mod infer;
 pub mod collect;
 pub mod coherence;
 
-#[auto_encode]
-#[auto_decode]
+#[deriving(Encodable, Decodable)]
 pub enum method_origin {
     // supertrait method invoked on "self" inside a default method
     // first field is supertrait ID;
@@ -98,8 +97,7 @@ pub enum method_origin {
 
 // details for a method invoked with a receiver whose type is a type parameter
 // with a bounded trait.
-#[auto_encode]
-#[auto_decode]
+#[deriving(Encodable, Decodable)]
 pub struct method_param {
     // the trait containing the method to be invoked
     trait_id: ast::def_id,
diff --git a/src/librustc/util/enum_set.rs b/src/librustc/util/enum_set.rs
index dae4bb69c61..2e6c4ee3eaa 100644
--- a/src/librustc/util/enum_set.rs
+++ b/src/librustc/util/enum_set.rs
@@ -8,11 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#[cfg(stage0)]
 use core;
 
 #[deriving(Eq, IterBytes)]
 pub struct EnumSet<E> {
-    bits: uint
+    // We must maintain the invariant that no bits are set
+    // for which no variant exists
+    priv bits: uint
 }
 
 pub trait CLike {
@@ -37,10 +40,18 @@ pub impl<E:CLike> EnumSet<E> {
         (self.bits & e.bits) != 0
     }
 
+    fn intersection(&self, e: EnumSet<E>) -> EnumSet<E> {
+        EnumSet {bits: self.bits & e.bits}
+    }
+
     fn contains(&self, e: EnumSet<E>) -> bool {
         (self.bits & e.bits) == e.bits
     }
 
+    fn union(&self, e: EnumSet<E>) -> EnumSet<E> {
+        EnumSet {bits: self.bits | e.bits}
+    }
+
     fn add(&mut self, e: E) {
         self.bits |= bit(e);
     }
diff --git a/src/librustpkg/conditions.rs b/src/librustpkg/conditions.rs
index 5b19a3bd660..680e0924d79 100644
--- a/src/librustpkg/conditions.rs
+++ b/src/librustpkg/conditions.rs
@@ -28,3 +28,7 @@ condition! {
 condition! {
     missing_pkg_files: (super::PkgId) -> ();
 }
+
+condition! {
+    bad_pkg_id: (super::Path, ~str) -> ::util::PkgId;
+}
diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs
index 477a7af4550..bbd8d092354 100644
--- a/src/librustpkg/path_util.rs
+++ b/src/librustpkg/path_util.rs
@@ -10,12 +10,10 @@
 
 // rustpkg utilities having to do with paths and directories
 
-use util::PkgId;
+pub use util::{PkgId, RemotePath, LocalPath};
 use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
 use core::os::mkdir_recursive;
-
-#[deriving(Eq)]
-pub enum OutputType { Main, Lib, Bench, Test }
+pub use util::{normalize, OutputType, Main, Lib, Bench, Test};
 
 /// Returns the value of RUST_PATH, as a list
 /// of Paths. In general this should be read from the
@@ -31,24 +29,6 @@ pub static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;
 /// succeeded.
 pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, u_rwx) }
 
-/// Replace all occurrences of '-' in the stem part of path with '_'
-/// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux
-/// as the same name
-pub fn normalize(p: ~Path) -> ~Path {
-    match p.filestem() {
-        None => p,
-        Some(st) => {
-            let replaced = str::replace(st, "-", "_");
-            if replaced != st {
-                ~p.with_filestem(replaced)
-            }
-            else {
-                p
-            }
-        }
-    }
-}
-
 // n.b. So far this only handles local workspaces
 // n.b. The next three functions ignore the package version right
 // now. Should fix that.
@@ -56,7 +36,7 @@ pub fn normalize(p: ~Path) -> ~Path {
 /// True if there's a directory in <workspace> with
 /// pkgid's short name
 pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
-    let pkgpath = workspace.push("src").push(pkgid.path.to_str());
+    let pkgpath = workspace.push("src").push(pkgid.local_path.to_str());
     os::path_is_dir(&pkgpath)
 }
 
@@ -64,34 +44,58 @@ pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
 /// Doesn't check that it exists.
 pub fn pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
     let result = workspace.push("src");
-    result.push(pkgid.path.to_str())
+    result.push(pkgid.local_path.to_str())
 }
 
 /// Figure out what the executable name for <pkgid> in <workspace>'s build
 /// directory is, and if the file exists, return it.
 pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
     let mut result = workspace.push("build");
-    result = result.push_rel(&pkgid.path);
     // should use a target-specific subdirectory
-    result = mk_output_path(Main, fmt!("%s-%s", pkgid.path.to_str(), pkgid.version.to_str()),
-                                       result);
+    result = mk_output_path(Main, pkgid, &result);
     debug!("built_executable_in_workspace: checking whether %s exists",
            result.to_str());
     if os::path_exists(&result) {
         Some(result)
     }
     else {
+        // This is not an error, but it's worth logging it
+        error!(fmt!("built_executable_in_workspace: %s does not exist", result.to_str()));
         None
     }
 }
 
-/// Figure out what the library name for <pkgid> in <workspace>'s build
+/// Figure out what the test name for <pkgid> in <workspace>'s build
 /// directory is, and if the file exists, return it.
-pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
+pub fn built_test_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
+    output_in_workspace(pkgid, workspace, Test)
+}
+
+/// Figure out what the test name for <pkgid> in <workspace>'s build
+/// directory is, and if the file exists, return it.
+pub fn built_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
+    output_in_workspace(pkgid, workspace, Bench)
+}
+
+fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Option<Path> {
     let mut result = workspace.push("build");
-    result = result.push_rel(&pkgid.path);
     // should use a target-specific subdirectory
-    result = mk_output_path(Lib, pkgid.path.to_str(), result);
+    result = mk_output_path(what, pkgid, &result);
+    debug!("output_in_workspace: checking whether %s exists",
+           result.to_str());
+    if os::path_exists(&result) {
+        Some(result)
+    }
+    else {
+        error!(fmt!("output_in_workspace: %s does not exist", result.to_str()));
+        None
+    }
+}
+
+/// Figure out what the library name for <pkgid> in <workspace>'s build
+/// directory is, and if the file exists, return it.
+pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
+    let result = mk_output_path(Lib, pkgid, &workspace.push("build"));
     debug!("built_library_in_workspace: checking whether %s exists",
            result.to_str());
 
@@ -100,8 +104,7 @@ pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Pat
     let dir_contents = os::list_dir(&result.pop());
     debug!("dir has %? entries", dir_contents.len());
 
-    // n.b. This code assumes the pkgid's path only has one element
-    let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, pkgid.path.to_str());
+    let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, pkgid.short_name);
     let lib_filetype = fmt!("%s%s", pkgid.version.to_str(), os::consts::DLL_SUFFIX);
 
     debug!("lib_prefix = %s and lib_filetype = %s", lib_prefix, lib_filetype);
@@ -173,12 +176,14 @@ pub fn target_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
 
 /// Returns the test executable that would be installed for <pkgid>
 /// in <workspace>
+/// note that we *don't* install test executables, so this is just for unit testing
 pub fn target_test_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
     target_file_in_workspace(pkgid, workspace, Test)
 }
 
 /// Returns the bench executable that would be installed for <pkgid>
 /// in <workspace>
+/// note that we *don't* install bench executables, so this is just for unit testing
 pub fn target_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
     target_file_in_workspace(pkgid, workspace, Bench)
 }
@@ -187,18 +192,14 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path,
                             what: OutputType) -> Path {
     use conditions::bad_path::cond;
 
-    let (subdir, create_dir) = match what {
-        Main => ("bin", true), Lib => ("lib", true), Test | Bench => ("build", false)
+    let subdir = match what {
+        Lib => "lib", Main | Test | Bench => "bin"
     };
     let result = workspace.push(subdir);
-    if create_dir {
-        if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) {
-            cond.raise((copy result,
-                        fmt!("I couldn't create the %s dir", subdir)));
-        }
+    if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) {
+        cond.raise((copy result, fmt!("I couldn't create the %s dir", subdir)));
     }
-    mk_output_path(what, pkgid.path.to_str(), result)
-
+    mk_output_path(what, pkgid, &result)
 }
 
 /// Return the directory for <pkgid>'s build artifacts in <workspace>.
@@ -209,7 +210,7 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
     let mut result = workspace.push("build");
     // n.b. Should actually use a target-specific
     // subdirectory of build/
-    result = result.push(normalize(~copy pkgid.path).to_str());
+    result = result.push_rel(&*pkgid.local_path);
     if os::path_exists(&result) || os::mkdir_recursive(&result, u_rwx) {
         result
     }
@@ -220,15 +221,26 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
 
 /// Return the output file for a given directory name,
 /// given whether we're building a library and whether we're building tests
-pub fn mk_output_path(what: OutputType, short_name: ~str, dir: Path) -> Path {
-    match what {
-        Lib => dir.push(os::dll_filename(short_name)),
-        _ => dir.push(fmt!("%s%s%s", short_name,
+pub fn mk_output_path(what: OutputType, pkg_id: &PkgId, workspace: &Path) -> Path {
+    let short_name_with_version = pkg_id.short_name_with_version();
+    // Not local_path.dir_path()! For package foo/bar/blat/, we want
+    // the executable blat-0.5 to live under blat/
+    let dir = workspace.push_rel(&*pkg_id.local_path);
+    debug!("mk_output_path: short_name = %s, path = %s",
+           if what == Lib { copy short_name_with_version } else { copy pkg_id.short_name },
+           dir.to_str());
+    let output_path = match what {
+        // this code is duplicated from elsewhere; fix this
+        Lib => dir.push(os::dll_filename(short_name_with_version)),
+        // executable names *aren't* versioned
+        _ => dir.push(fmt!("%s%s%s", copy pkg_id.short_name,
                            match what {
                                Test => "test",
                                Bench => "bench",
                                _     => ""
                            }
                            os::EXE_SUFFIX))
-    }
+    };
+    debug!("mk_output_path: returning %s", output_path.to_str());
+    output_path
 }
diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc
index 884f0a73589..a69613776ef 100644
--- a/src/librustpkg/rustpkg.rc
+++ b/src/librustpkg/rustpkg.rc
@@ -30,12 +30,10 @@ use rustc::metadata::filesearch;
 use std::{getopts};
 use syntax::{ast, diagnostic};
 use util::*;
-use path_util::normalize;
-use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace};
+use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace, u_rwx};
 use path_util::{built_executable_in_workspace, built_library_in_workspace};
 use path_util::{target_executable_in_workspace, target_library_in_workspace};
 use workspace::pkg_parent_workspaces;
-use rustc::driver::session::{lib_crate, bin_crate, crate_type};
 use context::Ctx;
 
 mod conditions;
@@ -159,27 +157,6 @@ impl<'self> PkgScript<'self> {
 impl Ctx {
 
     fn run(&self, cmd: ~str, args: ~[~str]) {
-        let root = util::root();
-
-        util::need_dir(&root);
-        util::need_dir(&root.push(~"work"));
-        util::need_dir(&root.push(~"lib"));
-        util::need_dir(&root.push(~"bin"));
-        util::need_dir(&root.push(~"tmp"));
-
-        fn sep_name_vers(in: ~str) -> (Option<~str>, Option<~str>) {
-            let mut name = None;
-            let mut vers = None;
-
-            for str::each_split_char(in, '@') |s| {
-                if      name.is_none() { name = Some(s.to_owned()); }
-                else if vers.is_none() { vers = Some(s.to_owned()); }
-                else                   { break;               }
-            }
-
-            (name, vers)
-        }
-
         match cmd {
             ~"build" => {
                 if args.len() < 1 {
@@ -229,9 +206,7 @@ impl Ctx {
                     return usage::uninstall();
                 }
 
-                let (name, vers) = sep_name_vers(copy args[0]);
-
-                self.prefer(name.get(), vers);
+                self.prefer(args[0], None);
             }
             ~"test" => {
                 self.test();
@@ -241,20 +216,16 @@ impl Ctx {
                     return usage::uninstall();
                 }
 
-                let (name, vers) = sep_name_vers(copy args[0]);
-
-                self.uninstall(name.get(), vers);
+                self.uninstall(args[0], None);
             }
             ~"unprefer" => {
                 if args.len() < 1 {
                     return usage::uninstall();
                 }
 
-                let (name, vers) = sep_name_vers(copy args[0]);
-
-                self.unprefer(name.get(), vers);
+                self.unprefer(args[0], None);
             }
-            _ => fail!("reached an unhandled command")
+            _ => fail!(fmt!("I don't know the command `%s`", cmd))
         }
     }
 
@@ -269,7 +240,7 @@ impl Ctx {
         debug!("Destination dir = %s", build_dir.to_str());
 
         // Create the package source
-        let mut src = PkgSrc::new(&workspace.push("src"), &build_dir, pkgid);
+        let mut src = PkgSrc::new(workspace, &build_dir, pkgid);
         debug!("Package src = %?", src);
 
         // Is there custom build logic? If so, use it
@@ -307,7 +278,6 @@ impl Ctx {
             // Build it!
             src.build(&build_dir, cfgs, self.sysroot_opt);
         }
-
     }
 
     fn clean(&self, workspace: &Path, id: &PkgId)  {
@@ -319,7 +289,7 @@ impl Ctx {
         util::note(fmt!("Cleaning package %s (removing directory %s)",
                         id.to_str(), dir.to_str()));
         if os::path_exists(&dir) {
-            util::remove_dir_r(&dir);
+            os::remove_dir_recursive(&dir);
             util::note(fmt!("Removed directory %s", dir.to_str()));
         }
 
@@ -337,6 +307,8 @@ impl Ctx {
         // Should use RUST_PATH in the future.
         // Also should use workcache to not build if not necessary.
         self.build(workspace, id);
+        debug!("install: workspace = %s, id = %s", workspace.to_str(),
+               id.to_str());
 
         // Now copy stuff into the install dirs
         let maybe_executable = built_executable_in_workspace(id, workspace);
@@ -344,104 +316,29 @@ impl Ctx {
         let target_exec = target_executable_in_workspace(id, workspace);
         let target_lib = target_library_in_workspace(id, workspace);
 
+        debug!("target_exec = %s target_lib = %s \
+                maybe_executable = %? maybe_library = %?",
+               target_exec.to_str(), target_lib.to_str(),
+               maybe_executable, maybe_library);
+
         for maybe_executable.each |exec| {
             debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str());
-            if !os::copy_file(exec, &target_exec) {
+            if !(os::mkdir_recursive(&target_exec.dir_path(), u_rwx) &&
+                 os::copy_file(exec, &target_exec)) {
                 cond.raise((copy *exec, copy target_exec));
             }
         }
         for maybe_library.each |lib| {
             debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str());
-            if !os::copy_file(lib, &target_lib) {
+            if !(os::mkdir_recursive(&target_lib.dir_path(), u_rwx) &&
+                 os::copy_file(lib, &target_lib)) {
                 cond.raise((copy *lib, copy target_lib));
             }
         }
     }
 
-    fn fetch(&self, _dir: &Path, _url: ~str, _target: Option<~str>)  {
-        // stub
-        fail!("fetch not yet implemented");
-    }
-
-    fn fetch_curl(&self, dir: &Path, url: ~str)  {
-        util::note(fmt!("fetching from %s using curl", url));
-
-        let tar = dir.dir_path().push(&dir.file_path().to_str() + ~".tar");
-
-        if run::program_output(~"curl", ~[~"-f", ~"-s",
-                                          ~"-o", tar.to_str(),
-                                          url]).status != 0 {
-            util::error(~"fetching failed: downloading using curl failed");
-
-            fail!();
-        }
-
-        if run::program_output(~"tar", ~[~"-x", ~"--strip-components=1",
-                                         ~"-C", dir.to_str(), ~"-f",
-                                         tar.to_str()]).status != 0 {
-            util::error(~"fetching failed: extracting using tar failed" +
-                        ~"(is it a valid tar archive?)");
-
-           fail!();
-        }
-    }
-
-    fn fetch_git(&self, dir: &Path, url: ~str, mut target: Option<~str>)  {
-        util::note(fmt!("fetching from %s using git", url));
-
-        // Git can't clone into a non-empty directory
-        util::remove_dir_r(dir);
-
-        if run::program_output(~"git", ~[~"clone", url,
-                                         dir.to_str()]).status != 0 {
-            util::error(~"fetching failed: can't clone repository");
-            fail!();
-        }
-
-        if !target.is_none() {
-            let mut success = true;
-
-            do util::temp_change_dir(dir) {
-                success = run::program_output(~"git",
-                                              ~[~"checkout",
-                                                target.swap_unwrap()]).status != 0
-            }
-
-            if !success {
-                util::error(~"fetching failed: can't checkout target");
-                fail!();
-            }
-        }
-    }
-
-    fn prefer(&self, id: ~str, vers: Option<~str>)  {
-        let package = match util::get_pkg(id, vers) {
-            result::Ok(package) => package,
-            result::Err(err) => {
-                util::error(err);
-                fail!(); // Condition?
-            }
-        };
-        let name = package.id.path.to_str(); // ???
-
-        util::note(fmt!("preferring %s v%s", name, package.id.version.to_str()));
-
-        let bin_dir = util::root().push(~"bin");
-
-        for package.bins.each |&bin| {
-            let path = Path(bin);
-            let mut name = None;
-            for str::each_split_char(path.file_path().to_str(), '-') |s| {
-                name = Some(s.to_owned());
-                break;
-            }
-            let out = bin_dir.push(name.unwrap());
-
-            util::link_exe(&path, &out);
-            util::note(fmt!("linked %s", out.to_str()));
-        }
-
-        util::note(fmt!("preferred %s v%s", name, package.id.version.to_str()));
+    fn prefer(&self, _id: &str, _vers: Option<~str>)  {
+        fail!(~"prefer not yet implemented");
     }
 
     fn test(&self)  {
@@ -449,15 +346,16 @@ impl Ctx {
         fail!("test not yet implemented");
     }
 
-    fn uninstall(&self, _id: ~str, _vers: Option<~str>)  {
+    fn uninstall(&self, _id: &str, _vers: Option<~str>)  {
         fail!("uninstall not yet implemented");
     }
 
-    fn unprefer(&self, _id: ~str, _vers: Option<~str>)  {
+    fn unprefer(&self, _id: &str, _vers: Option<~str>)  {
         fail!("unprefer not yet implemented");
     }
 }
 
+
 pub fn main() {
     io::println("WARNING: The Rust package manager is experimental and may be unstable");
 
@@ -518,32 +416,6 @@ pub struct Crate {
     cfgs: ~[~str]
 }
 
-pub struct Listener {
-    cmds: ~[~str],
-    cb: ~fn()
-}
-
-pub fn run(listeners: ~[Listener]) {
-    let rcmd = copy os::args()[2];
-    let mut found = false;
-
-    for listeners.each |listener| {
-        for listener.cmds.each |&cmd| {
-            if cmd == rcmd {
-                (listener.cb)();
-
-                found = true;
-
-                break;
-            }
-        }
-    }
-
-    if !found {
-        os::set_exit_status(42);
-    }
-}
-
 pub impl Crate {
 
     fn new(p: &Path) -> Crate {
@@ -602,10 +474,6 @@ pub fn src_dir() -> Path {
     os::getcwd()
 }
 
-condition! {
-    bad_pkg_id: (super::Path, ~str) -> ::util::PkgId;
-}
-
 // An enumeration of the unpacked source of a package workspace.
 // This contains a list of files found in the source workspace.
 pub struct PkgSrc {
@@ -641,17 +509,19 @@ impl PkgSrc {
     fn check_dir(&self) -> Path {
         use conditions::nonexistent_package::cond;
 
-        debug!("Pushing onto root: %s | %s", self.id.path.to_str(),
+        debug!("Pushing onto root: %s | %s", self.id.to_str(),
                self.root.to_str());
 
-        let dir = self.root.push_rel(&self.id.path).normalize();
+        let mut dir = self.root.push("src");
+        dir = dir.push(self.id.to_str()); // ?? Should this use the version number?
 
         debug!("Checking dir: %s", dir.to_str());
 
-        // tjc: Rather than erroring out, need to try downloading the
-        // contents of the path to a local directory (#5679)
         if !os::path_exists(&dir) {
-            cond.raise((copy self.id, ~"missing package dir"));
+            if !self.fetch_git() {
+                cond.raise((copy self.id, ~"supplied path for package dir does not \
+                    exist, and couldn't interpret it as a URL fragment"));
+            }
         }
 
         if !os::path_is_dir(&dir) {
@@ -662,6 +532,28 @@ impl PkgSrc {
         dir
     }
 
+    /// Try interpreting self's package id as a remote package, and try
+    /// fetching it and caching it in a local directory. If that didn't
+    /// work, return false.
+    /// (right now we only support git)
+    fn fetch_git(&self) -> bool {
+
+        let mut local = self.root.push("src");
+        local = local.push(self.id.to_str());
+        // Git can't clone into a non-empty directory
+        os::remove_dir_recursive(&local);
+
+        let url = fmt!("https://%s", self.id.remote_path.to_str());
+        util::note(fmt!("git clone %s %s", url, local.to_str()));
+
+        if run::program_output(~"git", ~[~"clone", copy url, local.to_str()]).status != 0 {
+            util::note(fmt!("fetching %s failed: can't clone repository", url));
+            return false;
+        }
+        true
+    }
+
+
     // If a file named "pkg.rs" in the current directory exists,
     // return the path for it. Otherwise, None
     fn package_script_option(&self, cwd: &Path) -> Option<Path> {
@@ -680,7 +572,7 @@ impl PkgSrc {
     /// Requires that dashes in p have already been normalized to
     /// underscores
     fn stem_matches(&self, p: &Path) -> bool {
-        let self_id = normalize(~copy self.id.path).filestem();
+        let self_id = self.id.local_path.filestem();
         if self_id == p.filestem() {
             return true;
         }
@@ -715,7 +607,7 @@ impl PkgSrc {
 
         let dir = self.check_dir();
         let prefix = dir.components.len();
-        debug!("Matching against %?", self.id.path.filestem());
+        debug!("Matching against %?", self.id.local_path.filestem());
         for os::walk_dir(&dir) |pth| {
             match pth.filename() {
                 Some(~"lib.rs") => push_crate(&mut self.libs,
@@ -752,8 +644,7 @@ impl PkgSrc {
                     src_dir: &Path,
                     crates: &[Crate],
                     cfgs: &[~str],
-                    test: bool, crate_type: crate_type) {
-
+                    what: OutputType) {
         for crates.each |&crate| {
             let path = &src_dir.push_rel(&crate.file).normalize();
             util::note(fmt!("build_crates: compiling %s", path.to_str()));
@@ -763,7 +654,7 @@ impl PkgSrc {
                                      dst_dir,
                                      crate.flags,
                                      crate.cfgs + cfgs,
-                                     false, test, crate_type);
+                                     false, what);
             if !result {
                 build_err::cond.raise(fmt!("build failure on %s",
                                            path.to_str()));
@@ -776,12 +667,13 @@ impl PkgSrc {
     fn build(&self, dst_dir: &Path, cfgs: ~[~str], maybe_sysroot: Option<@Path>) {
         let dir = self.check_dir();
         debug!("Building libs");
-        self.build_crates(maybe_sysroot, dst_dir, &dir, self.libs, cfgs, false, lib_crate);
+        self.build_crates(maybe_sysroot, dst_dir, &dir, self.libs, cfgs, Lib);
         debug!("Building mains");
-        self.build_crates(maybe_sysroot, dst_dir, &dir, self.mains, cfgs, false, bin_crate);
+        self.build_crates(maybe_sysroot, dst_dir, &dir, self.mains, cfgs, Main);
         debug!("Building tests");
-        self.build_crates(maybe_sysroot, dst_dir, &dir, self.tests, cfgs, true, bin_crate);
+        self.build_crates(maybe_sysroot, dst_dir, &dir, self.tests, cfgs, Test);
         debug!("Building benches");
-        self.build_crates(maybe_sysroot, dst_dir, &dir, self.benchs, cfgs, true, bin_crate);
+        self.build_crates(maybe_sysroot, dst_dir, &dir, self.benchs, cfgs, Bench);
     }
 }
+
diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs
index e661e758d41..8eba3f06de3 100644
--- a/src/librustpkg/tests.rs
+++ b/src/librustpkg/tests.rs
@@ -17,8 +17,8 @@ use std::tempfile::mkdtemp;
 use util::{PkgId, default_version};
 use path_util::{target_executable_in_workspace, target_library_in_workspace,
                target_test_in_workspace, target_bench_in_workspace,
-               make_dir_rwx, u_rwx};
-use core::os::mkdir_recursive;
+               make_dir_rwx, u_rwx, RemotePath, LocalPath, normalize,
+               built_bench_in_workspace, built_test_in_workspace};
 
 fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
     Ctx {
@@ -29,15 +29,22 @@ fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
 }
 
 fn fake_pkg() -> PkgId {
+    let sn = ~"bogus";
+    let remote = RemotePath(Path(sn));
     PkgId {
-        path: Path(~"bogus"),
+        local_path: normalize(copy remote),
+        remote_path: remote,
+        short_name: sn,
         version: default_version()
     }
 }
 
 fn remote_pkg() -> PkgId {
+    let remote = RemotePath(Path(~"github.com/catamorphism/test-pkg"));
     PkgId {
-        path: Path(~"github.com/catamorphism/test-pkg"),
+        local_path: normalize(copy remote),
+        remote_path: remote,
+        short_name: ~"test_pkg",
         version: default_version()
     }
 }
@@ -49,10 +56,11 @@ fn writeFile(file_path: &Path, contents: ~str) {
     out.write_line(contents);
 }
 
-fn mk_temp_workspace(short_name: &Path) -> Path {
+fn mk_temp_workspace(short_name: &LocalPath) -> Path {
     let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
-    let package_dir = workspace.push(~"src").push_rel(short_name);
-    assert!(mkdir_recursive(&package_dir, u_rwx));
+    // include version number in directory name
+    let package_dir = workspace.push(~"src").push(fmt!("%s-0.1", short_name.to_str()));
+    assert!(os::mkdir_recursive(&package_dir, u_rwx));
     // Create main, lib, test, and bench files
     writeFile(&package_dir.push(~"main.rs"),
               ~"fn main() { let _x = (); }");
@@ -85,7 +93,9 @@ fn test_sysroot() -> Path {
     self_path.pop()
 }
 
+// Ignored on i686 -- see #6517
 #[test]
+#[ignore(cfg(target_arch = "x86"))]
 fn test_make_dir_rwx() {
     let temp = &os::tmpdir();
     let dir = temp.push(~"quux");
@@ -99,12 +109,13 @@ fn test_make_dir_rwx() {
 }
 
 #[test]
+#[ignore(cfg(target_arch = "x86"))]
 fn test_install_valid() {
     let sysroot = test_sysroot();
     debug!("sysroot = %s", sysroot.to_str());
     let ctxt = fake_ctxt(Some(@sysroot));
     let temp_pkg_id = fake_pkg();
-    let temp_workspace = mk_temp_workspace(&temp_pkg_id.path);
+    let temp_workspace = mk_temp_workspace(&temp_pkg_id.local_path);
     // should have test, bench, lib, and main
     ctxt.install(&temp_workspace, &temp_pkg_id);
     // Check that all files exist
@@ -124,6 +135,7 @@ fn test_install_valid() {
 }
 
 #[test]
+#[ignore(cfg(target_arch = "x86"))]
 fn test_install_invalid() {
     use conditions::nonexistent_package::cond;
     use cond1 = conditions::missing_pkg_files::cond;
@@ -146,27 +158,80 @@ fn test_install_invalid() {
 }
 
 #[test]
-#[ignore(reason = "install from URL-fragment not yet implemented")]
+#[ignore(cfg(target_arch = "x86"))]
 fn test_install_url() {
+    let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
     let sysroot = test_sysroot();
     debug!("sysroot = %s", sysroot.to_str());
     let ctxt = fake_ctxt(Some(@sysroot));
     let temp_pkg_id = remote_pkg();
-    let temp_workspace = mk_temp_workspace(&temp_pkg_id.path);
     // should have test, bench, lib, and main
-    ctxt.install(&temp_workspace, &temp_pkg_id);
+    ctxt.install(&workspace, &temp_pkg_id);
     // Check that all files exist
-    let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
+    let exec = target_executable_in_workspace(&temp_pkg_id, &workspace);
     debug!("exec = %s", exec.to_str());
     assert!(os::path_exists(&exec));
     assert!(is_rwx(&exec));
-    let lib = target_library_in_workspace(&temp_pkg_id, &temp_workspace);
+    let lib = target_library_in_workspace(&temp_pkg_id, &workspace);
     debug!("lib = %s", lib.to_str());
     assert!(os::path_exists(&lib));
     assert!(is_rwx(&lib));
+    let built_test = built_test_in_workspace(&temp_pkg_id, &workspace).expect(~"test_install_url");
+    assert!(os::path_exists(&built_test));
+    let built_bench = built_bench_in_workspace(&temp_pkg_id,
+                                               &workspace).expect(~"test_install_url");
+    assert!(os::path_exists(&built_bench));
     // And that the test and bench executables aren't installed
-    assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, &temp_workspace)));
-    let bench = target_bench_in_workspace(&temp_pkg_id, &temp_workspace);
+    let test = target_test_in_workspace(&temp_pkg_id, &workspace);
+    assert!(!os::path_exists(&test));
+    debug!("test = %s", test.to_str());
+    let bench = target_bench_in_workspace(&temp_pkg_id, &workspace);
     debug!("bench = %s", bench.to_str());
     assert!(!os::path_exists(&bench));
 }
+
+#[test]
+fn test_package_ids_must_be_relative_path_like() {
+    use conditions::bad_pkg_id::cond;
+
+    /*
+    Okay:
+    - One identifier, with no slashes
+    - Several slash-delimited things, with no / at the root
+
+    Not okay:
+    - Empty string
+    - Absolute path (as per os::is_absolute)
+
+    */
+
+    let default_version_str = "0.1";
+    let addversion = |s| {
+        fmt!("%s-%s", s, default_version_str)
+    };
+
+    let whatever = PkgId::new("foo");
+
+    assert!(addversion("foo") == whatever.to_str());
+    assert!(addversion("github.com/mozilla/rust") ==
+            PkgId::new("github.com/mozilla/rust").to_str());
+
+    do cond.trap(|(p, e)| {
+        assert!("" == p.to_str());
+        assert!("0-length pkgid" == e);
+        copy whatever
+    }).in {
+        let x = PkgId::new("");
+        assert!(addversion("foo") == x.to_str());
+    }
+
+    do cond.trap(|(p, e)| {
+        assert!(p.to_str() == os::make_absolute(&Path("foo/bar/quux")).to_str());
+        assert!("absolute pkgid" == e);
+        copy whatever
+    }).in {
+        let z = PkgId::new(os::make_absolute(&Path("foo/bar/quux")).to_str());
+        assert!(addversion("foo") == z.to_str());
+    }
+
+}
diff --git a/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/src/main.rs b/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/main.rs
index 62785c06db3..62785c06db3 100644
--- a/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/src/main.rs
+++ b/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/main.rs
diff --git a/src/librustpkg/testsuite/pass/src/external-crate/src/main.rs b/src/librustpkg/testsuite/pass/src/external-crate/main.rs
index d094bcd6bba..d094bcd6bba 100644
--- a/src/librustpkg/testsuite/pass/src/external-crate/src/main.rs
+++ b/src/librustpkg/testsuite/pass/src/external-crate/main.rs
diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs
index e9c4b7fde55..4a9c276948a 100644
--- a/src/librustpkg/util.rs
+++ b/src/librustpkg/util.rs
@@ -13,20 +13,18 @@ use core::cmp::Ord;
 use core::hash::Streaming;
 use core::rt::io::Writer;
 use rustc::driver::{driver, session};
-use rustc::driver::session::{lib_crate, unknown_crate};
 use rustc::metadata::filesearch;
 use std::getopts::groups::getopts;
 use std::semver;
-use std::{json, term, getopts};
+use std::{term, getopts};
 use syntax::ast_util::*;
 use syntax::codemap::{dummy_sp, spanned, dummy_spanned};
 use syntax::ext::base::{mk_ctxt, ext_ctxt};
-use syntax::ext::build;
 use syntax::{ast, attr, codemap, diagnostic, fold};
-use syntax::ast::{meta_name_value, meta_list, attribute};
+use syntax::ast::{meta_name_value, meta_list};
 use syntax::attr::{mk_attr};
 use rustc::back::link::output_type_exe;
-use rustc::driver::session::{lib_crate, unknown_crate, crate_type};
+use rustc::driver::session::{lib_crate, bin_crate};
 
 static Commands: &'static [&'static str] =
     &["build", "clean", "do", "info", "install", "prefer", "test", "uninstall",
@@ -83,20 +81,34 @@ impl ToStr for Version {
     }
 }
 
+#[deriving(Eq)]
+pub enum OutputType { Main, Lib, Bench, Test }
+
 /// Placeholder
 pub fn default_version() -> Version { ExactRevision(0.1) }
 
-// Path-fragment identifier of a package such as
-// 'github.com/graydon/test'; path must be a relative
-// path with >=1 component.
+/// Path-fragment identifier of a package such as
+/// 'github.com/graydon/test'; path must be a relative
+/// path with >=1 component.
 pub struct PkgId {
-    path: Path,
+    /// Remote path: for example, github.com/mozilla/quux-whatever
+    remote_path: RemotePath,
+    /// Local path: for example, /home/quux/github.com/mozilla/quux_whatever
+    /// Note that '-' normalizes to '_' when mapping a remote path
+    /// onto a local path
+    /// Also, this will change when we implement #6407, though we'll still
+    /// need to keep track of separate local and remote paths
+    local_path: LocalPath,
+    /// Short name. This is the local path's filestem, but we store it
+    /// redundantly so as to not call get() everywhere (filestem() returns an
+    /// option)
+    short_name: ~str,
     version: Version
 }
 
 pub impl PkgId {
     fn new(s: &str) -> PkgId {
-        use bad_pkg_id::cond;
+        use conditions::bad_pkg_id::cond;
 
         let p = Path(s);
         if p.is_absolute {
@@ -105,31 +117,32 @@ pub impl PkgId {
         if p.components.len() < 1 {
             return cond.raise((p, ~"0-length pkgid"));
         }
+        let remote_path = RemotePath(p);
+        let local_path = normalize(copy remote_path);
+        let short_name = (copy local_path).filestem().expect(fmt!("Strange path! %s", s));
         PkgId {
-            path: p,
+            local_path: local_path,
+            remote_path: remote_path,
+            short_name: short_name,
             version: default_version()
         }
     }
 
     fn hash(&self) -> ~str {
-        fmt!("%s-%s-%s", self.path.to_str(),
-             hash(self.path.to_str() + self.version.to_str()),
+        fmt!("%s-%s-%s", self.remote_path.to_str(),
+             hash(self.remote_path.to_str() + self.version.to_str()),
              self.version.to_str())
     }
 
+    fn short_name_with_version(&self) -> ~str {
+        fmt!("%s-%s", self.short_name, self.version.to_str())
+    }
 }
 
 impl ToStr for PkgId {
     fn to_str(&self) -> ~str {
         // should probably use the filestem and not the whole path
-        fmt!("%s-%s", self.path.to_str(),
-             // Replace dots with -s in the version
-             // this is because otherwise rustc will think
-             // that foo-0.1 has .1 as its extension
-             // (Temporary hack until I figure out how to
-             // get rustc to not name the object file
-             // foo-0.o if I pass in foo-0.1 to build_output_filenames)
-             str::replace(self.version.to_str(), ".", "-"))
+        fmt!("%s-%s", self.local_path.to_str(), self.version.to_str())
     }
 }
 
@@ -156,26 +169,6 @@ pub fn is_cmd(cmd: &str) -> bool {
     Commands.any(|&c| c == cmd)
 }
 
-pub fn parse_name(id: ~str) -> result::Result<~str, ~str> {
-    let mut last_part = None;
-
-    for str::each_split_char(id, '.') |part| {
-        for str::each_char(part) |char| {
-            if char::is_whitespace(char) {
-                return result::Err(
-                    ~"could not parse id: contains whitespace");
-            } else if char::is_uppercase(char) {
-                return result::Err(
-                    ~"could not parse id: should be all lowercase");
-            }
-        }
-        last_part = Some(part.to_owned());
-    }
-    if last_part.is_none() { return result::Err(~"could not parse id: is empty"); }
-
-    result::Ok(last_part.unwrap())
-}
-
 struct ListenerFn {
     cmds: ~[~str],
     span: codemap::span,
@@ -248,52 +241,6 @@ fn fold_item(ctx: @mut ReadyCtx,
     res
 }
 
-fn add_pkg_module(ctx: @mut ReadyCtx, m: ast::_mod) -> ast::_mod {
-    let listeners = mk_listener_vec(ctx);
-    let ext_cx = ctx.ext_cx;
-    let item = quote_item! (
-        mod __pkg {
-            extern mod rustpkg (vers="0.7-pre");
-            static listeners : &[rustpkg::Listener] = $listeners;
-            #[main]
-            fn main() {
-                rustpkg::run(listeners);
-            }
-        }
-    );
-    ast::_mod {
-        items: vec::append_one(/*bad*/copy m.items, item.get()),
-        .. m
-    }
-}
-
-fn mk_listener_vec(ctx: @mut ReadyCtx) -> @ast::expr {
-    let descs = do ctx.fns.map |listener| {
-        mk_listener_rec(ctx, listener)
-    };
-    let ext_cx = ctx.ext_cx;
-    build::mk_slice_vec_e(ext_cx, dummy_sp(), descs)
-}
-
-fn mk_listener_rec(ctx: @mut ReadyCtx, listener: &ListenerFn) -> @ast::expr {
-    let span = listener.span;
-    let cmds = do listener.cmds.map |&cmd| {
-        let ext_cx = ctx.ext_cx;
-        build::mk_base_str(ext_cx, span, cmd)
-    };
-
-    let ext_cx = ctx.ext_cx;
-    let cmds_expr = build::mk_slice_vec_e(ext_cx, span, cmds);
-    let cb_expr = build::mk_path(ext_cx, span, copy listener.path);
-
-    quote_expr!(
-        Listener {
-            cmds: $cmds_expr,
-            cb: $cb_expr
-        }
-    )
-}
-
 /// Generate/filter main function, add the list of commands, etc.
 pub fn ready_crate(sess: session::Session,
                    crate: @ast::crate) -> @ast::crate {
@@ -375,67 +322,6 @@ pub fn hash(data: ~str) -> ~str {
     hasher.result_str()
 }
 
-pub fn temp_change_dir<T>(dir: &Path, cb: &fn() -> T) {
-    let cwd = os::getcwd();
-
-    os::change_dir(dir);
-    cb();
-    os::change_dir(&cwd);
-}
-
-pub fn touch(path: &Path) {
-    match io::mk_file_writer(path, ~[io::Create]) {
-        result::Ok(writer) => writer.write_line(~""),
-        _ => {}
-    }
-}
-
-pub fn remove_dir_r(path: &Path) {
-    for os::walk_dir(path) |&file| {
-        let mut cdir = file;
-
-        loop {
-            if os::path_is_dir(&cdir) {
-                os::remove_dir(&cdir);
-            } else {
-                os::remove_file(&cdir);
-            }
-
-            cdir = cdir.dir_path();
-
-            if cdir == *path { break; }
-        }
-    }
-
-    os::remove_dir(path);
-}
-
-pub fn wait_for_lock(path: &Path) {
-    if os::path_exists(path) {
-        warn(fmt!("the database appears locked, please wait (or rm %s)",
-                        path.to_str()));
-
-        loop {
-            if !os::path_exists(path) { break; }
-        }
-    }
-}
-
-pub fn load_pkgs() -> result::Result<~[json::Json], ~str> {
-    fail!("load_pkg not implemented");
-}
-
-pub fn get_pkg(_id: ~str,
-               _vers: Option<~str>) -> result::Result<Pkg, ~str> {
-    fail!("get_pkg not implemented");
-}
-
-pub fn add_pkg(pkg: &Pkg) -> bool {
-    note(fmt!("Would be adding package, but add_pkg is not yet implemented %s",
-         pkg.to_str()));
-    false
-}
-
 // FIXME (#4432): Use workcache to only compile when needed
 pub fn compile_input(sysroot: Option<@Path>,
                      pkg_id: &PkgId,
@@ -444,31 +330,24 @@ pub fn compile_input(sysroot: Option<@Path>,
                      flags: &[~str],
                      cfgs: &[~str],
                      opt: bool,
-                     test: bool,
-                     crate_type: session::crate_type) -> bool {
-
-    // Want just the directory component here
-    let pkg_filename = pkg_id.path.filename().expect(~"Weird pkg id");
-    let short_name = fmt!("%s-%s", pkg_filename, pkg_id.version.to_str());
+                     what: OutputType) -> bool {
 
     assert!(in_file.components.len() > 1);
     let input = driver::file_input(copy *in_file);
-    debug!("compile_input: %s / %?", in_file.to_str(), crate_type);
+    debug!("compile_input: %s / %?", in_file.to_str(), what);
     // tjc: by default, use the package ID name as the link name
     // not sure if we should support anything else
 
-    let binary = @copy os::args()[0];
-    let building_library = match crate_type {
-        lib_crate | unknown_crate => true,
-        _ => false
-    };
+    let binary = @(copy os::args()[0]);
+    let building_library = what == Lib;
 
     let out_file = if building_library {
-        out_dir.push(os::dll_filename(short_name))
+        out_dir.push(os::dll_filename(pkg_id.short_name))
     }
     else {
-        out_dir.push(short_name + if test { ~"test" } else { ~"" }
-                     + os::EXE_SUFFIX)
+        out_dir.push(pkg_id.short_name + match what {
+            Test => ~"test", Bench => ~"bench", Main | Lib => ~""
+        } + os::EXE_SUFFIX)
     };
 
     debug!("compiling %s into %s",
@@ -478,18 +357,24 @@ pub fn compile_input(sysroot: Option<@Path>,
     debug!("cfgs: %s", str::connect(cfgs, ~" "));
     debug!("compile_input's sysroot = %?", sysroot);
 
+    let crate_type = match what {
+        Lib => lib_crate,
+        Test | Bench | Main => bin_crate
+    };
     let matches = getopts(~[~"-Z", ~"time-passes"]
-                          + if building_library { ~[~"--lib"] }
-                            else if test { ~[~"--test"] }
-                            // bench?
-                            else { ~[] }
+                          + match what {
+                              Lib => ~[~"--lib"],
+                              // --test compiles both #[test] and #[bench] fns
+                              Test | Bench => ~[~"--test"],
+                              Main => ~[]
+                          }
                           + flags
                           + cfgs.flat_map(|&c| { ~[~"--cfg", c] }),
                           driver::optgroups()).get();
     let mut options = session::options {
         crate_type: crate_type,
         optimize: if opt { session::Aggressive } else { session::No },
-        test: test,
+        test: what == Test || what == Bench,
         maybe_sysroot: sysroot,
         addl_lib_search_paths: ~[copy *out_dir],
         // output_type should be conditional
@@ -540,26 +425,27 @@ pub fn compile_crate_from_input(input: &driver::input,
             debug!("Calling compile_upto, outputs = %?", outputs);
             let (crate, _) = driver::compile_upto(sess, copy cfg, input,
                                                   driver::cu_parse, Some(outputs));
+            let mut crate = crate;
 
             debug!("About to inject link_meta info...");
             // Inject the inferred link_meta info if it's not already there
             // (assumes that name and vers are the only linkage metas)
-            let mut crate_to_use = crate;
 
             debug!("How many attrs? %?", attr::find_linkage_metas(crate.node.attrs).len());
 
             if attr::find_linkage_metas(crate.node.attrs).is_empty() {
-                crate_to_use = add_attrs(copy *crate,
-                    ~[mk_attr(@dummy_spanned(meta_list(@~"link",
-                                                  // change PkgId to have a <shortname> field?
-                    ~[@dummy_spanned(meta_name_value(@~"name",
-                                                    mk_string_lit(@pkg_id.path.filestem().get()))),
-                      @dummy_spanned(meta_name_value(@~"vers",
-                                                    mk_string_lit(@pkg_id.version.to_str())))])))]);
+                crate = @codemap::respan(crate.span, ast::crate_ {
+                    attrs: ~[mk_attr(@dummy_spanned(
+                        meta_list(@~"link",
+                                  ~[@dummy_spanned(meta_name_value(@~"name",
+                                        mk_string_lit(@(copy pkg_id.short_name)))),
+                                    @dummy_spanned(meta_name_value(@~"vers",
+                                        mk_string_lit(@(copy pkg_id.version.to_str()))))])))],
+                    ..copy crate.node});
             }
 
-            driver::compile_rest(sess, cfg, what, Some(outputs), Some(crate_to_use));
-            crate_to_use
+            driver::compile_rest(sess, cfg, what, Some(outputs), Some(crate));
+            crate
         }
     }
 }
@@ -573,30 +459,41 @@ pub fn exe_suffix() -> ~str { ~".exe" }
 #[cfg(target_os = "macos")]
 pub fn exe_suffix() -> ~str { ~"" }
 
-
-/// Returns a copy of crate `c` with attributes `attrs` added to its
-/// attributes
-fn add_attrs(mut c: ast::crate, new_attrs: ~[attribute]) -> @ast::crate {
-    c.node.attrs += new_attrs;
-    @c
-}
-
 // Called by build_crates
 // FIXME (#4432): Use workcache to only compile when needed
 pub fn compile_crate(sysroot: Option<@Path>, pkg_id: &PkgId,
                      crate: &Path, dir: &Path,
                      flags: &[~str], cfgs: &[~str], opt: bool,
-                     test: bool, crate_type: crate_type) -> bool {
+                     what: OutputType) -> bool {
     debug!("compile_crate: crate=%s, dir=%s", crate.to_str(), dir.to_str());
     debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str());
     for flags.each |&fl| {
         debug!("+++ %s", fl);
     }
-    compile_input(sysroot, pkg_id,
-                  crate, dir, flags, cfgs, opt, test, crate_type)
+    compile_input(sysroot, pkg_id, crate, dir, flags, cfgs, opt, what)
+}
+
+// normalize should be the only way to construct a LocalPath
+// (though this isn't enforced)
+/// Replace all occurrences of '-' in the stem part of path with '_'
+/// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux
+/// as the same name
+pub fn normalize(p_: RemotePath) -> LocalPath {
+    let RemotePath(p) = p_;
+    match p.filestem() {
+        None => LocalPath(p),
+        Some(st) => {
+            let replaced = str::replace(st, "-", "_");
+            if replaced != st {
+                LocalPath(p.with_filestem(replaced))
+            }
+            else {
+                LocalPath(p)
+            }
+        }
+    }
 }
 
-
 #[cfg(windows)]
 pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
     /* FIXME (#1768): Investigate how to do this on win32
@@ -628,9 +525,13 @@ pub fn mk_string_lit(s: @~str) -> ast::lit {
     }
 }
 
+/// Wrappers to prevent local and remote paths from getting confused
+pub struct RemotePath (Path);
+pub struct LocalPath (Path);
+
 #[cfg(test)]
 mod test {
-    use super::{is_cmd, parse_name};
+    use super::is_cmd;
 
     #[test]
     fn test_is_cmd() {
@@ -645,9 +546,4 @@ mod test {
         assert!(is_cmd(~"unprefer"));
     }
 
-    #[test]
-    fn test_parse_name() {
-        assert!(parse_name(~"org.mozilla.servo").get() == ~"servo");
-        assert!(parse_name(~"org. mozilla.servo 2131").is_err());
-    }
 }
diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs
index 8941dbfd20e..cb9f735bce8 100644
--- a/src/librustpkg/workspace.rs
+++ b/src/librustpkg/workspace.rs
@@ -21,9 +21,10 @@ pub fn pkg_parent_workspaces(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool
         workspace_contains_package_id(pkgid, ws));
     if workspaces.is_empty() {
         // tjc: make this a condition
-        fail!("Package %s not found in any of the following workspaces: %s",
-              pkgid.path.to_str(),
-              rust_path().to_str());
+        fail!("Package %s not found in any of \
+                    the following workspaces: %s",
+                   pkgid.remote_path.to_str(),
+                   rust_path().to_str());
     }
     for workspaces.each |ws| {
         if action(ws) {
diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs
index 07c1c226d1f..64f78d5ab7b 100644
--- a/src/libstd/ebml.rs
+++ b/src/libstd/ebml.rs
@@ -779,7 +779,7 @@ pub mod writer {
     priv impl Encoder {
         // used internally to emit things like the vector length and so on
         fn _emit_tagged_uint(&mut self, t: EbmlEncoderTag, v: uint) {
-            assert!(v <= 0xFFFF_FFFF_u); // FIXME(#6130) assert warns on 32-bit
+            assert!(v <= 0xFFFF_FFFF_u);
             self.wr_tagged_u32(t as uint, v as u32);
         }
 
diff --git a/src/libstd/json.rs b/src/libstd/json.rs
index 7702b46ddcb..270cf675c87 100644
--- a/src/libstd/json.rs
+++ b/src/libstd/json.rs
@@ -1331,26 +1331,20 @@ mod tests {
 
     use std::serialize::Decodable;
 
-    #[auto_encode]
-    #[auto_decode]
-    #[deriving(Eq)]
+    #[deriving(Eq, Encodable, Decodable)]
     enum Animal {
         Dog,
         Frog(~str, int)
     }
 
-    #[auto_encode]
-    #[auto_decode]
-    #[deriving(Eq)]
+    #[deriving(Eq, Encodable, Decodable)]
     struct Inner {
         a: (),
         b: uint,
         c: ~[~str],
     }
 
-    #[auto_encode]
-    #[auto_decode]
-    #[deriving(Eq)]
+    #[deriving(Eq, Encodable, Decodable)]
     struct Outer {
         inner: ~[Inner],
     }
diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs
index 8cf2da3a1e8..46f50eafec1 100644
--- a/src/libstd/rc.rs
+++ b/src/libstd/rc.rs
@@ -11,7 +11,11 @@
 /** Task-local reference counted smart pointers
 
 Task-local reference counted smart pointers are an alternative to managed boxes with deterministic
-destruction. They are restricted to containing `Owned` types in order to prevent cycles.
+destruction. They are restricted to containing types that are either `Owned` or `Const` (or both) to
+prevent cycles.
+
+Neither `Rc<T>` or `RcMut<T>` is ever `Owned` and `RcMut<T>` is never `Const`. If `T` is `Const`, a
+cycle cannot be created with `Rc<T>` because there is no way to modify it after creation.
 
 */
 
@@ -30,16 +34,26 @@ pub struct Rc<T> {
     priv ptr: *mut RcBox<T>,
 }
 
-pub impl<T: Owned> Rc<T> {
-    fn new(value: T) -> Rc<T> {
-        unsafe {
-            let ptr = malloc(sys::size_of::<RcBox<T>>() as size_t) as *mut RcBox<T>;
-            assert!(!ptr::is_null(ptr));
-            intrinsics::move_val_init(&mut *ptr, RcBox{value: value, count: 1});
-            Rc{ptr: ptr}
-        }
+priv impl<T> Rc<T> {
+    unsafe fn new(value: T) -> Rc<T> {
+        let ptr = malloc(sys::size_of::<RcBox<T>>() as size_t) as *mut RcBox<T>;
+        assert!(!ptr::is_null(ptr));
+        intrinsics::move_val_init(&mut *ptr, RcBox{value: value, count: 1});
+        Rc{ptr: ptr}
     }
+}
+
+// FIXME: #6516: should be a static method
+pub fn rc_from_owned<T: Owned>(value: T) -> Rc<T> {
+    unsafe { Rc::new(value) }
+}
 
+// FIXME: #6516: should be a static method
+pub fn rc_from_const<T: Const>(value: T) -> Rc<T> {
+    unsafe { Rc::new(value) }
+}
+
+pub impl<T> Rc<T> {
     #[inline(always)]
     fn borrow<'r>(&'r self) -> &'r T {
         unsafe { cast::copy_lifetime(self, &(*self.ptr).value) }
@@ -48,7 +62,7 @@ pub impl<T: Owned> Rc<T> {
 
 #[unsafe_destructor]
 #[cfg(not(stage0))]
-impl<T: Owned> Drop for Rc<T> {
+impl<T> Drop for Rc<T> {
     fn finalize(&self) {
         unsafe {
             (*self.ptr).count -= 1;
@@ -62,7 +76,7 @@ impl<T: Owned> Drop for Rc<T> {
 
 #[unsafe_destructor]
 #[cfg(stage0)]
-impl<T: Owned> Drop for Rc<T> {
+impl<T> Drop for Rc<T> {
     fn finalize(&self) {
         unsafe {
             (*self.ptr).count -= 1;
@@ -75,7 +89,8 @@ impl<T: Owned> Drop for Rc<T> {
 }
 
 
-impl<T: Owned> Clone for Rc<T> {
+impl<T> Clone for Rc<T> {
+    /// Return a shallow copy of the reference counted pointer.
     #[inline]
     fn clone(&self) -> Rc<T> {
         unsafe {
@@ -85,19 +100,48 @@ impl<T: Owned> Clone for Rc<T> {
     }
 }
 
+impl<T: DeepClone> DeepClone for Rc<T> {
+    /// Return a deep copy of the reference counted pointer.
+    #[inline]
+    fn deep_clone(&self) -> Rc<T> {
+        unsafe { Rc::new(self.borrow().deep_clone()) }
+    }
+}
+
 #[cfg(test)]
 mod test_rc {
     use super::*;
+    use core::cell::Cell;
+
+    #[test]
+    fn test_clone() {
+        let x = rc_from_owned(Cell(5));
+        let y = x.clone();
+        do x.borrow().with_mut_ref |inner| {
+            *inner = 20;
+        }
+        assert_eq!(y.borrow().take(), 20);
+    }
+
+    #[test]
+    fn test_deep_clone() {
+        let x = rc_from_owned(Cell(5));
+        let y = x.deep_clone();
+        do x.borrow().with_mut_ref |inner| {
+            *inner = 20;
+        }
+        assert_eq!(y.borrow().take(), 5);
+    }
 
     #[test]
     fn test_simple() {
-        let x = Rc::new(5);
+        let x = rc_from_const(5);
         assert_eq!(*x.borrow(), 5);
     }
 
     #[test]
-    fn test_clone() {
-        let x = Rc::new(5);
+    fn test_simple_clone() {
+        let x = rc_from_const(5);
         let y = x.clone();
         assert_eq!(*x.borrow(), 5);
         assert_eq!(*y.borrow(), 5);
@@ -105,7 +149,7 @@ mod test_rc {
 
     #[test]
     fn test_destructor() {
-        let x = Rc::new(~5);
+        let x = rc_from_owned(~5);
         assert_eq!(**x.borrow(), 5);
     }
 }
@@ -137,43 +181,55 @@ pub struct RcMut<T> {
     priv ptr: *mut RcMutBox<T>,
 }
 
-pub impl<T: Owned> RcMut<T> {
-    fn new(value: T) -> RcMut<T> {
-        unsafe {
-            let ptr = malloc(sys::size_of::<RcMutBox<T>>() as size_t) as *mut RcMutBox<T>;
-            assert!(!ptr::is_null(ptr));
-            intrinsics::move_val_init(&mut *ptr, RcMutBox{value: value, count: 1, borrow: Nothing});
-            RcMut{ptr: ptr}
-        }
+priv impl<T> RcMut<T> {
+    unsafe fn new(value: T) -> RcMut<T> {
+        let ptr = malloc(sys::size_of::<RcMutBox<T>>() as size_t) as *mut RcMutBox<T>;
+        assert!(!ptr::is_null(ptr));
+        intrinsics::move_val_init(&mut *ptr, RcMutBox{value: value, count: 1, borrow: Nothing});
+        RcMut{ptr: ptr}
     }
+}
+
+// FIXME: #6516: should be a static method
+pub fn rc_mut_from_owned<T: Owned>(value: T) -> RcMut<T> {
+    unsafe { RcMut::new(value) }
+}
+
+// FIXME: #6516: should be a static method
+pub fn rc_mut_from_const<T: Const>(value: T) -> RcMut<T> {
+    unsafe { RcMut::new(value) }
+}
 
+pub impl<T> RcMut<T> {
     /// Fails if there is already a mutable borrow of the box
     #[inline]
-    fn with_borrow(&self, f: &fn(&T)) {
+    fn with_borrow<U>(&self, f: &fn(&T) -> U) -> U {
         unsafe {
             assert!((*self.ptr).borrow != Mutable);
             let previous = (*self.ptr).borrow;
             (*self.ptr).borrow = Immutable;
-            f(&(*self.ptr).value);
+            let res = f(&(*self.ptr).value);
             (*self.ptr).borrow = previous;
+            res
         }
     }
 
     /// Fails if there is already a mutable or immutable borrow of the box
     #[inline]
-    fn with_mut_borrow(&self, f: &fn(&mut T)) {
+    fn with_mut_borrow<U>(&self, f: &fn(&mut T) -> U) -> U {
         unsafe {
             assert!((*self.ptr).borrow == Nothing);
             (*self.ptr).borrow = Mutable;
-            f(&mut (*self.ptr).value);
+            let res = f(&mut (*self.ptr).value);
             (*self.ptr).borrow = Nothing;
+            res
         }
     }
 }
 
 #[unsafe_destructor]
 #[cfg(not(stage0))]
-impl<T: Owned> Drop for RcMut<T> {
+impl<T> Drop for RcMut<T> {
     fn finalize(&self) {
         unsafe {
             (*self.ptr).count -= 1;
@@ -187,7 +243,7 @@ impl<T: Owned> Drop for RcMut<T> {
 
 #[unsafe_destructor]
 #[cfg(stage0)]
-impl<T: Owned> Drop for RcMut<T> {
+impl<T> Drop for RcMut<T> {
     fn finalize(&self) {
         unsafe {
             (*self.ptr).count -= 1;
@@ -199,7 +255,8 @@ impl<T: Owned> Drop for RcMut<T> {
     }
 }
 
-impl<T: Owned> Clone for RcMut<T> {
+impl<T> Clone for RcMut<T> {
+    /// Return a shallow copy of the reference counted pointer.
     #[inline]
     fn clone(&self) -> RcMut<T> {
         unsafe {
@@ -209,13 +266,48 @@ impl<T: Owned> Clone for RcMut<T> {
     }
 }
 
+impl<T: DeepClone> DeepClone for RcMut<T> {
+    /// Return a deep copy of the reference counted pointer.
+    #[inline]
+    fn deep_clone(&self) -> RcMut<T> {
+        do self.with_borrow |x| {
+            // FIXME: #6497: should avoid freeze (slow)
+            unsafe { RcMut::new(x.deep_clone()) }
+        }
+    }
+}
+
 #[cfg(test)]
 mod test_rc_mut {
     use super::*;
 
     #[test]
+    fn test_clone() {
+        let x = rc_mut_from_owned(5);
+        let y = x.clone();
+        do x.with_mut_borrow |value| {
+            *value = 20;
+        }
+        do y.with_borrow |value| {
+            assert_eq!(*value, 20);
+        }
+    }
+
+    #[test]
+    fn test_deep_clone() {
+        let x = rc_mut_from_const(5);
+        let y = x.deep_clone();
+        do x.with_mut_borrow |value| {
+            *value = 20;
+        }
+        do y.with_borrow |value| {
+            assert_eq!(*value, 5);
+        }
+    }
+
+    #[test]
     fn borrow_many() {
-        let x = RcMut::new(5);
+        let x = rc_mut_from_owned(5);
         let y = x.clone();
 
         do x.with_borrow |a| {
@@ -231,7 +323,7 @@ mod test_rc_mut {
 
     #[test]
     fn modify() {
-        let x = RcMut::new(5);
+        let x = rc_mut_from_const(5);
         let y = x.clone();
 
         do y.with_mut_borrow |a| {
@@ -246,14 +338,14 @@ mod test_rc_mut {
 
     #[test]
     fn release_immutable() {
-        let x = RcMut::new(5);
+        let x = rc_mut_from_owned(5);
         do x.with_borrow |_| {}
         do x.with_mut_borrow |_| {}
     }
 
     #[test]
     fn release_mutable() {
-        let x = RcMut::new(5);
+        let x = rc_mut_from_const(5);
         do x.with_mut_borrow |_| {}
         do x.with_borrow |_| {}
     }
@@ -261,7 +353,7 @@ mod test_rc_mut {
     #[test]
     #[should_fail]
     fn frozen() {
-        let x = RcMut::new(5);
+        let x = rc_mut_from_owned(5);
         let y = x.clone();
 
         do x.with_borrow |_| {
@@ -273,7 +365,7 @@ mod test_rc_mut {
     #[test]
     #[should_fail]
     fn mutable_dupe() {
-        let x = RcMut::new(5);
+        let x = rc_mut_from_const(5);
         let y = x.clone();
 
         do x.with_mut_borrow |_| {
@@ -285,7 +377,7 @@ mod test_rc_mut {
     #[test]
     #[should_fail]
     fn mutable_freeze() {
-        let x = RcMut::new(5);
+        let x = rc_mut_from_owned(5);
         let y = x.clone();
 
         do x.with_mut_borrow |_| {
@@ -297,7 +389,7 @@ mod test_rc_mut {
     #[test]
     #[should_fail]
     fn restore_freeze() {
-        let x = RcMut::new(5);
+        let x = rc_mut_from_const(5);
         let y = x.clone();
 
         do x.with_borrow |_| {
diff --git a/src/libstd/time.rs b/src/libstd/time.rs
index e731f679221..202b96f9797 100644
--- a/src/libstd/time.rs
+++ b/src/libstd/time.rs
@@ -29,9 +29,7 @@ pub mod rustrt {
 }
 
 /// A record specifying a time value in seconds and nanoseconds.
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct Timespec { sec: i64, nsec: i32 }
 
 /*
@@ -100,9 +98,7 @@ pub fn tzset() {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct Tm {
     tm_sec: i32, // seconds after the minute ~[0-60]
     tm_min: i32, // minutes after the hour ~[0-59]
diff --git a/src/libstd/workcache.rs b/src/libstd/workcache.rs
index a9e4ec50c7c..f173df60df8 100644
--- a/src/libstd/workcache.rs
+++ b/src/libstd/workcache.rs
@@ -92,9 +92,7 @@ use core::util::replace;
 *
 */
 
-#[deriving(Eq)]
-#[auto_encode]
-#[auto_decode]
+#[deriving(Eq, Encodable, Decodable)]
 struct WorkKey {
     kind: ~str,
     name: ~str
diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs
index ee62bb270b8..1b166dcf366 100644
--- a/src/libsyntax/abi.rs
+++ b/src/libsyntax/abi.rs
@@ -58,9 +58,7 @@ enum AbiArchitecture {
     Archs(u32)  // Multiple architectures (bitset)
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct AbiSet {
     priv bits: u32   // each bit represents one of the abis below
 }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index f77d00ce9b1..dcbbd7ab531 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -47,9 +47,7 @@ pub type SyntaxContext = uint;
 pub type SCTable = ~[SyntaxContext_];
 pub static empty_ctxt : uint = 0;
 
-#[deriving(Eq)]
-#[auto_encode]
-#[auto_decode]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum SyntaxContext_ {
     EmptyCtxt,
     Mark (Mrk,SyntaxContext),
@@ -115,9 +113,7 @@ impl to_bytes::IterBytes for ident {
 // Functions may or may not have names.
 pub type fn_ident = Option<ident>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct Lifetime {
     id: node_id,
     span: span,
@@ -142,9 +138,7 @@ impl to_bytes::IterBytes for Lifetime {
 // for instance: core::cmp::Eq  .  It's represented
 // as a sequence of identifiers, along with a bunch
 // of supporting information.
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct Path {
     span: span,
     global: bool,
@@ -157,9 +151,7 @@ pub type crate_num = int;
 
 pub type node_id = int;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct def_id {
     crate: crate_num,
     node: node_id,
@@ -168,9 +160,7 @@ pub struct def_id {
 pub static local_crate: crate_num = 0;
 pub static crate_node_id: node_id = 0;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 // The AST represents all type param bounds as types.
 // typeck::collect::compute_bounds matches these against
 // the "special" built-in traits (see middle::lang_items) and
@@ -180,18 +170,14 @@ pub enum TyParamBound {
     RegionTyParamBound
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct TyParam {
     ident: ident,
     id: node_id,
     bounds: @OptVec<TyParamBound>
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct Generics {
     lifetimes: OptVec<Lifetime>,
     ty_params: OptVec<TyParam>
@@ -209,9 +195,7 @@ pub impl Generics {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum def {
     def_fn(def_id, purity),
     def_static_method(/* method */ def_id,
@@ -248,9 +232,7 @@ pub type crate_cfg = ~[@meta_item];
 
 pub type crate = spanned<crate_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct crate_ {
     module: _mod,
     attrs: ~[attribute],
@@ -259,9 +241,7 @@ pub struct crate_ {
 
 pub type meta_item = spanned<meta_item_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum meta_item_ {
     meta_word(@~str),
     meta_list(@~str, ~[@meta_item]),
@@ -270,9 +250,7 @@ pub enum meta_item_ {
 
 pub type blk = spanned<blk_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct blk_ {
     view_items: ~[@view_item],
     stmts: ~[@stmt],
@@ -281,26 +259,20 @@ pub struct blk_ {
     rules: blk_check_mode,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct pat {
     id: node_id,
     node: pat_,
     span: span,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct field_pat {
     ident: ident,
     pat: @pat,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum binding_mode {
     bind_by_copy,
     bind_by_ref(mutability),
@@ -334,9 +306,7 @@ impl to_bytes::IterBytes for binding_mode {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum pat_ {
     pat_wild,
     // A pat_ident may either be a new bound variable,
@@ -361,9 +331,7 @@ pub enum pat_ {
     pat_vec(~[@pat], Option<@pat>, ~[@pat])
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum mutability { m_mutbl, m_imm, m_const, }
 
 #[cfg(stage0)]
@@ -379,9 +347,7 @@ impl to_bytes::IterBytes for mutability {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum Sigil {
     BorrowedSigil,
     OwnedSigil,
@@ -411,9 +377,7 @@ impl ToStr for Sigil {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum vstore {
     // FIXME (#3469): Change uint to @expr (actually only constant exprs)
     vstore_fixed(Option<uint>),     // [1,2,3,4]
@@ -422,9 +386,7 @@ pub enum vstore {
     vstore_slice(Option<@Lifetime>) // &'foo? [1,2,3,4]
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum expr_vstore {
     expr_vstore_uniq,                  // ~[1,2,3,4]
     expr_vstore_box,                   // @[1,2,3,4]
@@ -433,9 +395,7 @@ pub enum expr_vstore {
     expr_vstore_mut_slice,             // &mut [1,2,3,4]
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum binop {
     add,
     subtract,
@@ -457,9 +417,7 @@ pub enum binop {
     gt,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum unop {
     box(mutability),
     uniq(mutability),
@@ -470,9 +428,7 @@ pub enum unop {
 
 pub type stmt = spanned<stmt_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum stmt_ {
     stmt_decl(@decl, node_id),
 
@@ -488,9 +444,7 @@ pub enum stmt_ {
 
 // FIXME (pending discussion of #1697, #2178...): local should really be
 // a refinement on pat.
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct local_ {
     is_mutbl: bool,
     ty: @Ty,
@@ -503,23 +457,17 @@ pub type local = spanned<local_>;
 
 pub type decl = spanned<decl_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum decl_ { decl_local(~[@local]), decl_item(@item), }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct arm {
     pats: ~[@pat],
     guard: Option<@expr>,
     body: blk,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct field_ {
     mutbl: mutability,
     ident: ident,
@@ -528,14 +476,10 @@ pub struct field_ {
 
 pub type field = spanned<field_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum blk_check_mode { default_blk, unsafe_blk, }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct expr {
     id: node_id,
     // Extra node ID is only used for index, assign_op, unary, binary, method
@@ -545,18 +489,14 @@ pub struct expr {
     span: span,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum CallSugar {
     NoSugar,
     DoSugar,
     ForSugar
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum expr_ {
     expr_vstore(@expr, expr_vstore),
     expr_vec(~[@expr], mutability),
@@ -627,9 +567,7 @@ pub enum expr_ {
 // else knows what to do with them, so you'll probably get a syntax
 // error.
 //
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 #[doc="For macro invocations; parsing is delegated to the macro"]
 pub enum token_tree {
     // a single token
@@ -702,9 +640,7 @@ pub enum token_tree {
 //
 pub type matcher = spanned<matcher_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum matcher_ {
     // match one token
     match_tok(::parse::token::Token),
@@ -717,18 +653,14 @@ pub enum matcher_ {
 
 pub type mac = spanned<mac_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum mac_ {
     mac_invoc_tt(@Path,~[token_tree]),   // new macro-invocation
 }
 
 pub type lit = spanned<lit_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum lit_ {
     lit_str(@~str),
     lit_int(i64, int_ty),
@@ -742,17 +674,13 @@ pub enum lit_ {
 
 // NB: If you change this, you'll probably want to change the corresponding
 // type structure in middle/ty.rs as well.
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct mt {
     ty: @Ty,
     mutbl: mutability,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct ty_field_ {
     ident: ident,
     mt: mt,
@@ -760,9 +688,7 @@ pub struct ty_field_ {
 
 pub type ty_field = spanned<ty_field_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct ty_method {
     ident: ident,
     attrs: ~[attribute],
@@ -774,9 +700,7 @@ pub struct ty_method {
     span: span,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 // A trait method is either required (meaning it doesn't have an
 // implementation, just a signature) or provided (meaning it has a default
 // implementation).
@@ -785,9 +709,7 @@ pub enum trait_method {
     provided(@method),
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum int_ty { ty_i, ty_char, ty_i8, ty_i16, ty_i32, ty_i64, }
 
 impl ToStr for int_ty {
@@ -809,9 +731,7 @@ impl to_bytes::IterBytes for int_ty {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum uint_ty { ty_u, ty_u8, ty_u16, ty_u32, ty_u64, }
 
 impl ToStr for uint_ty {
@@ -833,9 +753,7 @@ impl to_bytes::IterBytes for uint_ty {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum float_ty { ty_f, ty_f32, ty_f64, }
 
 impl ToStr for float_ty {
@@ -858,9 +776,7 @@ impl to_bytes::IterBytes for float_ty {
 }
 
 // NB Eq method appears below.
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct Ty {
     id: node_id,
     node: ty_,
@@ -868,9 +784,7 @@ pub struct Ty {
 }
 
 // Not represented directly in the AST, referred to by name through a ty_path.
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum prim_ty {
     ty_int(int_ty),
     ty_uint(uint_ty),
@@ -879,9 +793,7 @@ pub enum prim_ty {
     ty_bool,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum Onceness {
     Once,
     Many
@@ -909,21 +821,18 @@ impl to_bytes::IterBytes for Onceness {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct TyClosure {
     sigil: Sigil,
     region: Option<@Lifetime>,
     lifetimes: OptVec<Lifetime>,
     purity: purity,
     onceness: Onceness,
-    decl: fn_decl
+    decl: fn_decl,
+    bounds: OptVec<TyParamBound>
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct TyBareFn {
     purity: purity,
     abis: AbiSet,
@@ -931,9 +840,7 @@ pub struct TyBareFn {
     decl: fn_decl
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum ty_ {
     ty_nil,
     ty_bot, /* bottom type */
@@ -967,17 +874,13 @@ impl to_bytes::IterBytes for Ty {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum asm_dialect {
     asm_att,
     asm_intel
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct inline_asm {
     asm: @~str,
     clobbers: @~str,
@@ -988,9 +891,7 @@ pub struct inline_asm {
     dialect: asm_dialect
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct arg {
     is_mutbl: bool,
     ty: @Ty,
@@ -998,18 +899,14 @@ pub struct arg {
     id: node_id,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct fn_decl {
     inputs: ~[arg],
     output: @Ty,
     cf: ret_style,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum purity {
     pure_fn, // declared with "pure fn"
     unsafe_fn, // declared with "unsafe fn"
@@ -1041,9 +938,7 @@ impl to_bytes::IterBytes for purity {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum ret_style {
     noreturn, // functions with return type _|_ that always
               // raise an error or exit (i.e. never return to the caller)
@@ -1063,9 +958,7 @@ impl to_bytes::IterBytes for ret_style {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum explicit_self_ {
     sty_static,                                // no self
     sty_value,                                 // `self`
@@ -1102,9 +995,7 @@ impl to_bytes::IterBytes for explicit_self_ {
 
 pub type explicit_self = spanned<explicit_self_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct method {
     ident: ident,
     attrs: ~[attribute],
@@ -1119,23 +1010,17 @@ pub struct method {
     vis: visibility,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct _mod {
     view_items: ~[@view_item],
     items: ~[@item],
 }
 
 // Foreign mods can be named or anonymous
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum foreign_mod_sort { named, anonymous }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct foreign_mod {
     sort: foreign_mod_sort,
     abis: AbiSet,
@@ -1143,32 +1028,24 @@ pub struct foreign_mod {
     items: ~[@foreign_item],
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct variant_arg {
     ty: @Ty,
     id: node_id,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum variant_kind {
     tuple_variant_kind(~[variant_arg]),
     struct_variant_kind(@struct_def),
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct enum_def {
     variants: ~[variant],
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct variant_ {
     name: ident,
     attrs: ~[attribute],
@@ -1180,9 +1057,7 @@ pub struct variant_ {
 
 pub type variant = spanned<variant_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct path_list_ident_ {
     name: ident,
     id: node_id,
@@ -1192,9 +1067,7 @@ pub type path_list_ident = spanned<path_list_ident_>;
 
 pub type view_path = spanned<view_path_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum view_path_ {
 
     // quux = foo::bar::baz
@@ -1211,9 +1084,7 @@ pub enum view_path_ {
     view_path_list(@Path, ~[path_list_ident], node_id)
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct view_item {
     node: view_item_,
     attrs: ~[attribute],
@@ -1221,9 +1092,7 @@ pub struct view_item {
     span: span,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum view_item_ {
     view_item_extern_mod(ident, ~[@meta_item], node_id),
     view_item_use(~[@view_path]),
@@ -1235,15 +1104,11 @@ pub type attribute = spanned<attribute_>;
 // Distinguishes between attributes that decorate items and attributes that
 // are contained as statements within items. These two cases need to be
 // distinguished for pretty-printing.
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum attr_style { attr_outer, attr_inner, }
 
 // doc-comments are promoted to attributes that have is_sugared_doc = true
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct attribute_ {
     style: attr_style,
     value: @meta_item,
@@ -1257,17 +1122,13 @@ pub struct attribute_ {
   If this impl is an item_impl, the impl_id is redundant (it could be the
   same as the impl's node id).
  */
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct trait_ref {
     path: @Path,
     ref_id: node_id,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum visibility { public, private, inherited }
 
 impl visibility {
@@ -1279,9 +1140,7 @@ impl visibility {
     }
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct struct_field_ {
     kind: struct_field_kind,
     id: node_id,
@@ -1291,17 +1150,13 @@ pub struct struct_field_ {
 
 pub type struct_field = spanned<struct_field_>;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum struct_field_kind {
     named_field(ident, visibility),
     unnamed_field   // element of a tuple-like struct
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct struct_def {
     fields: ~[@struct_field], /* fields, not including ctor */
     /* ID of the constructor. This is only used for tuple- or enum-like
@@ -1313,9 +1168,7 @@ pub struct struct_def {
   FIXME (#3300): Should allow items to be anonymous. Right now
   we just use dummy names for anon items.
  */
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct item {
     ident: ident,
     attrs: ~[attribute],
@@ -1325,9 +1178,7 @@ pub struct item {
     span: span,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum item_ {
     item_const(@Ty, @expr),
     item_fn(fn_decl, purity, AbiSet, Generics, blk),
@@ -1345,9 +1196,7 @@ pub enum item_ {
     item_mac(mac),
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct foreign_item {
     ident: ident,
     attrs: ~[attribute],
@@ -1357,9 +1206,7 @@ pub struct foreign_item {
     vis: visibility,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum foreign_item_ {
     foreign_item_fn(fn_decl, purity, Generics),
     foreign_item_const(@Ty)
@@ -1368,9 +1215,7 @@ pub enum foreign_item_ {
 // The data we save and restore about an inlined item or method.  This is not
 // part of the AST that we parse from a file, but it becomes part of the tree
 // that we trans.
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub enum inlined_item {
     ii_item(@item),
     ii_method(def_id /* impl id */, @method),
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index a98e3002dcf..d4a67d61d94 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -370,8 +370,7 @@ pub fn empty_generics() -> Generics {
 // ______________________________________________________________________
 // Enumerating the IDs which appear in an AST
 
-#[auto_encode]
-#[auto_decode]
+#[deriving(Encodable, Decodable)]
 pub struct id_range {
     min: node_id,
     max: node_id,
@@ -413,7 +412,12 @@ pub fn id_visitor(vfn: @fn(node_id)) -> visit::vt<()> {
                       match vp.node {
                           view_path_simple(_, _, id) => vfn(id),
                           view_path_glob(_, id) => vfn(id),
-                          view_path_list(_, _, id) => vfn(id)
+                          view_path_list(_, ref paths, id) => {
+                              vfn(id);
+                              for paths.each |p| {
+                                  vfn(p.node.id);
+                              }
+                          }
                       }
                   }
               }
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index cd0b29f2a1e..44a368738fd 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -127,9 +127,7 @@ pub struct span {
     expn_info: Option<@ExpnInfo>
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Eq, Encodable, Decodable)]
 pub struct spanned<T> { node: T, span: span }
 
 impl cmp::Eq for span {
diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs
index 5c306aefc6a..6bb3ac5eba4 100644
--- a/src/libsyntax/ext/auto_encode.rs
+++ b/src/libsyntax/ext/auto_encode.rs
@@ -8,102 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-/*!
-
-The compiler code necessary to implement the #[auto_encode] and
-#[auto_decode] extension.  The idea here is that type-defining items may
-be tagged with #[auto_encode] and #[auto_decode], which will cause
-us to generate a little companion module with the same name as the item.
-
-For example, a type like:
-
-    #[auto_encode]
-    #[auto_decode]
-    struct Node {id: uint}
-
-would generate two implementations like:
-
-impl<S:std::serialize::Encoder> Encodable<S> for Node {
-    fn encode(&self, s: &S) {
-        do s.emit_struct("Node", 1) {
-            s.emit_field("id", 0, || s.emit_uint(self.id))
-        }
-    }
-}
-
-impl<D:Decoder> Decodable for node_id {
-    fn decode(d: &D) -> Node {
-        do d.read_struct("Node", 1) {
-            Node {
-                id: d.read_field(~"x", 0, || decode(d))
-            }
-        }
-    }
-}
-
-Other interesting scenarios are whe the item has type parameters or
-references other non-built-in types.  A type definition like:
-
-    #[auto_encode]
-    #[auto_decode]
-    struct spanned<T> {node: T, span: span}
-
-would yield functions like:
-
-    impl<
-        S: Encoder,
-        T: Encodable<S>
-    > spanned<T>: Encodable<S> {
-        fn encode<S:Encoder>(s: &S) {
-            do s.emit_rec {
-                s.emit_field("node", 0, || self.node.encode(s));
-                s.emit_field("span", 1, || self.span.encode(s));
-            }
-        }
-    }
-
-    impl<
-        D: Decoder,
-        T: Decodable<D>
-    > spanned<T>: Decodable<D> {
-        fn decode(d: &D) -> spanned<T> {
-            do d.read_rec {
-                {
-                    node: d.read_field(~"node", 0, || decode(d)),
-                    span: d.read_field(~"span", 1, || decode(d)),
-                }
-            }
-        }
-    }
-
-FIXME (#2810)--Hygiene. Search for "__" strings.  We also assume "std" is the
-standard library.
-
-Misc notes:
------------
-
-I use move mode arguments for ast nodes that will get inserted as is
-into the tree.  This is intended to prevent us from inserting the same
-node twice.
-
-*/
+/// Deprecated #[auto_encode] and #[auto_decode] syntax extensions
 
 use ast;
-use ast_util;
-use attr;
-use codemap;
 use codemap::span;
 use ext::base::*;
-use parse;
-use opt_vec;
-use opt_vec::OptVec;
-use ext::build;
-
-// Transitional reexports so qquote can find the paths it is looking for
-mod syntax {
-    pub use ext;
-    pub use parse;
-}
 
 pub fn expand_auto_encode(
     cx: @ext_ctxt,
@@ -111,53 +20,8 @@ pub fn expand_auto_encode(
     _mitem: @ast::meta_item,
     in_items: ~[@ast::item]
 ) -> ~[@ast::item] {
-    fn is_auto_encode(a: &ast::attribute) -> bool {
-        *attr::get_attr_name(a) == ~"auto_encode"
-    }
-
-    fn filter_attrs(item: @ast::item) -> @ast::item {
-        @ast::item {
-            attrs: item.attrs.filtered(|a| !is_auto_encode(a)),
-            .. copy *item
-        }
-    }
-
-    do vec::flat_map(in_items) |item| {
-        if item.attrs.any(is_auto_encode) {
-            match item.node {
-                ast::item_struct(ref struct_def, ref generics) => {
-                    let ser_impl = mk_struct_ser_impl(
-                        cx,
-                        item.span,
-                        item.ident,
-                        struct_def.fields,
-                        generics
-                    );
-
-                    ~[filter_attrs(*item), ser_impl]
-                },
-                ast::item_enum(ref enum_def, ref generics) => {
-                    let ser_impl = mk_enum_ser_impl(
-                        cx,
-                        item.span,
-                        item.ident,
-                        copy *enum_def,
-                        generics
-                    );
-
-                    ~[filter_attrs(*item), ser_impl]
-                },
-                _ => {
-                    cx.span_err(span, ~"#[auto_encode] can only be \
-                                        applied to structs, record types, \
-                                        and enum definitions");
-                    ~[*item]
-                }
-            }
-        } else {
-            ~[*item]
-        }
-    }
+    cx.span_err(span, "`#[auto_encode]` is deprecated, use `#[deriving(Encodable)]` instead");
+    in_items
 }
 
 pub fn expand_auto_decode(
@@ -166,1346 +30,6 @@ pub fn expand_auto_decode(
     _mitem: @ast::meta_item,
     in_items: ~[@ast::item]
 ) -> ~[@ast::item] {
-    fn is_auto_decode(a: &ast::attribute) -> bool {
-        *attr::get_attr_name(a) == ~"auto_decode"
-    }
-
-    fn filter_attrs(item: @ast::item) -> @ast::item {
-        @ast::item {
-            attrs: item.attrs.filtered(|a| !is_auto_decode(a)),
-            .. copy *item
-        }
-    }
-
-    do vec::flat_map(in_items) |item| {
-        if item.attrs.any(is_auto_decode) {
-            match item.node {
-                ast::item_struct(ref struct_def, ref generics) => {
-                    let deser_impl = mk_struct_deser_impl(
-                        cx,
-                        item.span,
-                        item.ident,
-                        struct_def.fields,
-                        generics
-                    );
-
-                    ~[filter_attrs(*item), deser_impl]
-                },
-                ast::item_enum(ref enum_def, ref generics) => {
-                    let deser_impl = mk_enum_deser_impl(
-                        cx,
-                        item.span,
-                        item.ident,
-                        copy *enum_def,
-                        generics
-                    );
-
-                    ~[filter_attrs(*item), deser_impl]
-                },
-                _ => {
-                    cx.span_err(span, ~"#[auto_decode] can only be \
-                                        applied to structs, record types, \
-                                        and enum definitions");
-                    ~[*item]
-                }
-            }
-        } else {
-            ~[*item]
-        }
-    }
-}
-
-trait ExtCtxtMethods {
-    fn bind_path(&self,
-                 span: span,
-                 ident: ast::ident,
-                 path: @ast::Path,
-                 bounds: @OptVec<ast::TyParamBound>)
-                 -> ast::TyParam;
-    fn expr(&self, span: span, node: ast::expr_) -> @ast::expr;
-    fn path(&self, span: span, strs: ~[ast::ident]) -> @ast::Path;
-    fn path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::Path;
-    fn path_tps(&self, span: span, strs: ~[ast::ident], tps: ~[@ast::Ty])
-                -> @ast::Path;
-    fn path_tps_global(&self,
-                       span: span,
-                       strs: ~[ast::ident],
-                       tps: ~[@ast::Ty])
-                       -> @ast::Path;
-    fn ty_path(&self, span: span, strs: ~[ast::ident], tps: ~[@ast::Ty])
-               -> @ast::Ty;
-    fn binder_pat(&self, span: span, nm: ast::ident) -> @ast::pat;
-    fn stmt(&self, expr: @ast::expr) -> @ast::stmt;
-    fn lit_str(&self, span: span, s: @~str) -> @ast::expr;
-    fn lit_uint(&self, span: span, i: uint) -> @ast::expr;
-    fn lambda0(&self, blk: ast::blk) -> @ast::expr;
-    fn lambda1(&self, blk: ast::blk, ident: ast::ident) -> @ast::expr;
-    fn blk(&self, span: span, stmts: ~[@ast::stmt]) -> ast::blk;
-    fn expr_blk(&self, expr: @ast::expr) -> ast::blk;
-    fn expr_path(&self, span: span, strs: ~[ast::ident]) -> @ast::expr;
-    fn expr_path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::expr;
-    fn expr_var(&self, span: span, var: &str) -> @ast::expr;
-    fn expr_self(&self, span: span) -> @ast::expr;
-    fn expr_field(&self, span: span, expr: @ast::expr, ident: ast::ident)
-                  -> @ast::expr;
-    fn expr_call(&self, span: span, expr: @ast::expr, args: ~[@ast::expr])
-                 -> @ast::expr;
-    fn expr_method_call(&self,
-                        span: span,
-                        expr: @ast::expr,
-                        ident: ast::ident,
-                        args: ~[@ast::expr])
-                        -> @ast::expr;
-    fn lambda_expr_0(&self, expr: @ast::expr) -> @ast::expr;
-    fn lambda_expr_1(&self, expr: @ast::expr, ident: ast::ident)
-                    -> @ast::expr;
-    fn lambda_stmts_0(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr;
-    fn lambda_stmts_1(&self,
-                      span: span,
-                      stmts: ~[@ast::stmt],
-                      ident: ast::ident)
-                      -> @ast::expr;
-}
-
-impl ExtCtxtMethods for @ext_ctxt {
-    fn bind_path(
-        &self,
-        _span: span,
-        ident: ast::ident,
-        path: @ast::Path,
-        bounds: @OptVec<ast::TyParamBound>
-    ) -> ast::TyParam {
-        let bound = ast::TraitTyParamBound(@ast::trait_ref {
-            ref_id: self.next_id(),
-            path: path
-        });
-
-        ast::TyParam {
-            ident: ident,
-            id: self.next_id(),
-            bounds: @bounds.prepend(bound)
-        }
-    }
-
-    fn expr(&self, span: span, node: ast::expr_) -> @ast::expr {
-        @ast::expr {
-            id: self.next_id(),
-            callee_id: self.next_id(),
-            node: node,
-            span: span,
-        }
-    }
-
-    fn path(&self, span: span, strs: ~[ast::ident]) -> @ast::Path {
-        @ast::Path {
-            span: span,
-            global: false,
-            idents: strs,
-            rp: None,
-            types: ~[]
-        }
-    }
-
-    fn path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::Path {
-        @ast::Path {
-            span: span,
-            global: true,
-            idents: strs,
-            rp: None,
-            types: ~[]
-        }
-    }
-
-    fn path_tps(
-        &self,
-        span: span,
-        strs: ~[ast::ident],
-        tps: ~[@ast::Ty]
-    ) -> @ast::Path {
-        @ast::Path {
-            span: span,
-            global: false,
-            idents: strs,
-            rp: None,
-            types: tps
-        }
-    }
-
-    fn path_tps_global(
-        &self,
-        span: span,
-        strs: ~[ast::ident],
-        tps: ~[@ast::Ty]
-    ) -> @ast::Path {
-        @ast::Path {
-            span: span,
-            global: true,
-            idents: strs,
-            rp: None,
-            types: tps
-        }
-    }
-
-    fn ty_path(
-        &self,
-        span: span,
-        strs: ~[ast::ident],
-        tps: ~[@ast::Ty]
-    ) -> @ast::Ty {
-        @ast::Ty {
-            id: self.next_id(),
-            node: ast::ty_path(
-                self.path_tps(span, strs, tps),
-                self.next_id()),
-            span: span,
-        }
-    }
-
-    fn binder_pat(&self, span: span, nm: ast::ident) -> @ast::pat {
-        @ast::pat {
-            id: self.next_id(),
-            node: ast::pat_ident(
-                ast::bind_by_ref(ast::m_imm),
-                self.path(span, ~[nm]),
-                None),
-            span: span,
-        }
-    }
-
-    fn stmt(&self, expr: @ast::expr) -> @ast::stmt {
-        @codemap::spanned { node: ast::stmt_semi(expr, self.next_id()),
-                       span: expr.span }
-    }
-
-    fn lit_str(&self, span: span, s: @~str) -> @ast::expr {
-        self.expr(
-            span,
-            ast::expr_vstore(
-                self.expr(
-                    span,
-                    ast::expr_lit(
-                        @codemap::spanned { node: ast::lit_str(s),
-                                        span: span})),
-                ast::expr_vstore_uniq))
-    }
-
-    fn lit_uint(&self, span: span, i: uint) -> @ast::expr {
-        self.expr(
-            span,
-            ast::expr_lit(
-                @codemap::spanned { node: ast::lit_uint(i as u64, ast::ty_u),
-                                span: span}))
-    }
-
-    fn lambda0(&self, blk: ast::blk) -> @ast::expr {
-        let ext_cx = *self;
-        let blk_e = self.expr(copy blk.span, ast::expr_block(copy blk));
-        quote_expr!( || $blk_e )
-    }
-
-    fn lambda1(&self, blk: ast::blk, ident: ast::ident) -> @ast::expr {
-        let ext_cx = *self;
-        let blk_e = self.expr(copy blk.span, ast::expr_block(copy blk));
-        quote_expr!( |$ident| $blk_e )
-    }
-
-    fn blk(&self, span: span, stmts: ~[@ast::stmt]) -> ast::blk {
-        codemap::spanned {
-            node: ast::blk_ {
-                view_items: ~[],
-                stmts: stmts,
-                expr: None,
-                id: self.next_id(),
-                rules: ast::default_blk,
-            },
-            span: span,
-        }
-    }
-
-    fn expr_blk(&self, expr: @ast::expr) -> ast::blk {
-        codemap::spanned {
-            node: ast::blk_ {
-                view_items: ~[],
-                stmts: ~[],
-                expr: Some(expr),
-                id: self.next_id(),
-                rules: ast::default_blk,
-            },
-            span: expr.span,
-        }
-    }
-
-    fn expr_path(&self, span: span, strs: ~[ast::ident]) -> @ast::expr {
-        self.expr(span, ast::expr_path(self.path(span, strs)))
-    }
-
-    fn expr_path_global(
-        &self,
-        span: span,
-        strs: ~[ast::ident]
-    ) -> @ast::expr {
-        self.expr(span, ast::expr_path(self.path_global(span, strs)))
-    }
-
-    fn expr_var(&self, span: span, var: &str) -> @ast::expr {
-        self.expr_path(span, ~[self.ident_of(var)])
-    }
-
-    fn expr_self(&self, span: span) -> @ast::expr {
-        self.expr(span, ast::expr_self)
-    }
-
-    fn expr_field(
-        &self,
-        span: span,
-        expr: @ast::expr,
-        ident: ast::ident
-    ) -> @ast::expr {
-        self.expr(span, ast::expr_field(expr, ident, ~[]))
-    }
-
-    fn expr_call(
-        &self,
-        span: span,
-        expr: @ast::expr,
-        args: ~[@ast::expr]
-    ) -> @ast::expr {
-        self.expr(span, ast::expr_call(expr, args, ast::NoSugar))
-    }
-
-    fn expr_method_call(
-        &self,
-        span: span,
-        expr: @ast::expr,
-        ident: ast::ident,
-        args: ~[@ast::expr]
-    ) -> @ast::expr {
-        self.expr(span,
-                  ast::expr_method_call(expr, ident, ~[], args, ast::NoSugar))
-    }
-
-    fn lambda_expr_0(&self, expr: @ast::expr) -> @ast::expr {
-        self.lambda0(self.expr_blk(expr))
-    }
-
-    fn lambda_expr_1(&self, expr: @ast::expr, ident: ast::ident)
-                    -> @ast::expr {
-        self.lambda1(self.expr_blk(expr), ident)
-    }
-
-    fn lambda_stmts_0(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr {
-        self.lambda0(self.blk(span, stmts))
-    }
-
-    fn lambda_stmts_1(&self,
-                      span: span,
-                      stmts: ~[@ast::stmt],
-                      ident: ast::ident)
-                      -> @ast::expr {
-        self.lambda1(self.blk(span, stmts), ident)
-    }
-}
-
-fn mk_impl(
-    cx: @ext_ctxt,
-    span: span,
-    ident: ast::ident,
-    ty_param: ast::TyParam,
-    path: @ast::Path,
-    generics: &ast::Generics,
-    f: &fn(@ast::Ty) -> @ast::method
-) -> @ast::item {
-    /*!
-     *
-     * Given that we are deriving auto-encode a type `T<'a, ...,
-     * 'z, A, ..., Z>`, creates an impl like:
-     *
-     *      impl<'a, ..., 'z, A:Tr, ..., Z:Tr> Tr for T<A, ..., Z> { ... }
-     *
-     * where Tr is either Serializable and Deserialize.
-     *
-     * FIXME(#5090): Remove code duplication between this and the code
-     * in deriving.rs
-     */
-
-
-    // Copy the lifetimes
-    let impl_lifetimes = generics.lifetimes.map(|l| {
-        build::mk_lifetime(cx, l.span, l.ident)
-    });
-
-    // All the type parameters need to bound to the trait.
-    let mut impl_tps = opt_vec::with(ty_param);
-    for generics.ty_params.each |tp| {
-        let t_bound = ast::TraitTyParamBound(@ast::trait_ref {
-            path: path,
-            ref_id: cx.next_id(),
-        });
-
-        impl_tps.push(ast::TyParam {
-            ident: tp.ident,
-            id: cx.next_id(),
-            bounds: @tp.bounds.prepend(t_bound)
-        })
-    }
-
-    let opt_trait = Some(@ast::trait_ref {
-        path: path,
-        ref_id: cx.next_id(),
-    });
-
-    let ty = cx.ty_path(
-        span,
-        ~[ident],
-        opt_vec::take_vec(generics.ty_params.map(
-            |tp| cx.ty_path(span, ~[tp.ident], ~[])))
-    );
-
-    let generics = ast::Generics {
-        lifetimes: impl_lifetimes,
-        ty_params: impl_tps
-    };
-
-    @ast::item {
-        // This is a new-style impl declaration.
-        // XXX: clownshoes
-        ident: parse::token::special_idents::clownshoes_extensions,
-        attrs: ~[],
-        id: cx.next_id(),
-        node: ast::item_impl(generics, opt_trait, ty, ~[f(ty)]),
-        vis: ast::public,
-        span: span,
-    }
-}
-
-fn mk_ser_impl(
-    cx: @ext_ctxt,
-    span: span,
-    ident: ast::ident,
-    generics: &ast::Generics,
-    body: @ast::expr
-) -> @ast::item {
-    // Make a path to the std::serialize::Encodable typaram.
-    let ty_param = cx.bind_path(
-        span,
-        cx.ident_of("__S"),
-        cx.path_global(
-            span,
-            ~[
-                cx.ident_of("std"),
-                cx.ident_of("serialize"),
-                cx.ident_of("Encoder"),
-            ]
-        ),
-        @opt_vec::Empty
-    );
-
-    // Make a path to the std::serialize::Encodable trait.
-    let path = cx.path_tps_global(
-        span,
-        ~[
-            cx.ident_of("std"),
-            cx.ident_of("serialize"),
-            cx.ident_of("Encodable"),
-        ],
-        ~[cx.ty_path(span, ~[cx.ident_of("__S")], ~[])]
-    );
-
-    mk_impl(
-        cx,
-        span,
-        ident,
-        ty_param,
-        path,
-        generics,
-        |_ty| mk_ser_method(cx, span, cx.expr_blk(body))
-    )
-}
-
-fn mk_deser_impl(
-    cx: @ext_ctxt,
-    span: span,
-    ident: ast::ident,
-    generics: &ast::Generics,
-    body: @ast::expr
-) -> @ast::item {
-    // Make a path to the std::serialize::Decodable typaram.
-    let ty_param = cx.bind_path(
-        span,
-        cx.ident_of("__D"),
-        cx.path_global(
-            span,
-            ~[
-                cx.ident_of("std"),
-                cx.ident_of("serialize"),
-                cx.ident_of("Decoder"),
-            ]
-        ),
-        @opt_vec::Empty
-    );
-
-    // Make a path to the std::serialize::Decodable trait.
-    let path = cx.path_tps_global(
-        span,
-        ~[
-            cx.ident_of("std"),
-            cx.ident_of("serialize"),
-            cx.ident_of("Decodable"),
-        ],
-        ~[cx.ty_path(span, ~[cx.ident_of("__D")], ~[])]
-    );
-
-    mk_impl(
-        cx,
-        span,
-        ident,
-        ty_param,
-        path,
-        generics,
-        |ty| mk_deser_method(cx, span, ty, cx.expr_blk(body))
-    )
-}
-
-fn mk_ser_method(
-    cx: @ext_ctxt,
-    span: span,
-    ser_body: ast::blk
-) -> @ast::method {
-    let ty_s = @ast::Ty {
-        id: cx.next_id(),
-        node: ast::ty_rptr(
-            None,
-            ast::mt {
-                ty: cx.ty_path(span, ~[cx.ident_of("__S")], ~[]),
-                mutbl: ast::m_mutbl
-            }
-        ),
-        span: span,
-    };
-
-    let ser_inputs = ~[ast::arg {
-        is_mutbl: false,
-        ty: ty_s,
-        pat: @ast::pat {
-            id: cx.next_id(),
-            node: ast::pat_ident(
-                ast::bind_by_copy,
-                ast_util::ident_to_path(span, cx.ident_of("__s")),
-                None),
-            span: span,
-        },
-        id: cx.next_id(),
-    }];
-
-    let ser_output = @ast::Ty {
-        id: cx.next_id(),
-        node: ast::ty_nil,
-        span: span,
-    };
-
-    let ser_decl = ast::fn_decl {
-        inputs: ser_inputs,
-        output: ser_output,
-        cf: ast::return_val,
-    };
-
-    @ast::method {
-        ident: cx.ident_of("encode"),
-        attrs: ~[],
-        generics: ast_util::empty_generics(),
-        explicit_self: codemap::spanned {
-            node: ast::sty_region(None, ast::m_imm),
-            span: span
-        },
-        purity: ast::impure_fn,
-        decl: ser_decl,
-        body: ser_body,
-        id: cx.next_id(),
-        span: span,
-        self_id: cx.next_id(),
-        vis: ast::public,
-    }
-}
-
-fn mk_deser_method(
-    cx: @ext_ctxt,
-    span: span,
-    ty: @ast::Ty,
-    deser_body: ast::blk
-) -> @ast::method {
-    let ty_d = @ast::Ty {
-        id: cx.next_id(),
-        node: ast::ty_rptr(
-            None,
-            ast::mt {
-                ty: cx.ty_path(span, ~[cx.ident_of("__D")], ~[]),
-                mutbl: ast::m_mutbl
-            }
-        ),
-        span: span,
-    };
-
-    let deser_inputs = ~[
-        ast::arg {
-            is_mutbl: false,
-            ty: ty_d,
-            pat: @ast::pat {
-                id: cx.next_id(),
-                node: ast::pat_ident(ast::bind_by_copy,
-                                     ast_util::ident_to_path(span,
-                                                             cx.ident_of(
-                                                                "__d")),
-                                     None),
-                span: span,
-            },
-            id: cx.next_id(),
-        }
-    ];
-
-    let deser_decl = ast::fn_decl {
-        inputs: deser_inputs,
-        output: ty,
-        cf: ast::return_val,
-    };
-
-    @ast::method {
-        ident: cx.ident_of("decode"),
-        attrs: ~[],
-        generics: ast_util::empty_generics(),
-        explicit_self: codemap::spanned { node: ast::sty_static, span: span },
-        purity: ast::impure_fn,
-        decl: deser_decl,
-        body: deser_body,
-        id: cx.next_id(),
-        span: span,
-        self_id: cx.next_id(),
-        vis: ast::public,
-    }
-}
-
-fn mk_struct_ser_impl(
-    cx: @ext_ctxt,
-    span: span,
-    ident: ast::ident,
-    fields: &[@ast::struct_field],
-    generics: &ast::Generics
-) -> @ast::item {
-    let fields = do mk_struct_fields(fields).mapi |idx, field| {
-        // ast for `|__s| self.$(name).encode(__s)`
-        let expr_lambda = cx.lambda_expr_1(
-            cx.expr_method_call(
-                span,
-                cx.expr_field(span, cx.expr_self(span), field.ident),
-                cx.ident_of(~"encode"),
-                ~[cx.expr_var(span, "__s")]
-            ),
-            cx.ident_of("__s")
-        );
-
-        // ast for `__s.emit_struct_field($(name), $(idx), $(expr_lambda))`
-        cx.stmt(
-            cx.expr_method_call(
-                span,
-                cx.expr_var(span, "__s"),
-                cx.ident_of("emit_struct_field"),
-                ~[
-                    cx.lit_str(span, @cx.str_of(field.ident)),
-                    cx.lit_uint(span, idx),
-                    expr_lambda,
-                ]
-            )
-        )
-    };
-
-    // ast for `__s.emit_struct($(name), |__s| $(fields))`
-    let ser_body = cx.expr_method_call(
-        span,
-        cx.expr_var(span, "__s"),
-        cx.ident_of("emit_struct"),
-        ~[
-            cx.lit_str(span, @cx.str_of(ident)),
-            cx.lit_uint(span, fields.len()),
-            cx.lambda_stmts_1(span, fields, cx.ident_of("__s")),
-        ]
-    );
-
-    mk_ser_impl(cx, span, ident, generics, ser_body)
-}
-
-fn mk_struct_deser_impl(
-    cx: @ext_ctxt,
-    span: span,
-    ident: ast::ident,
-    fields: &[@ast::struct_field],
-    generics: &ast::Generics
-) -> @ast::item {
-    let fields = do mk_struct_fields(fields).mapi |idx, field| {
-        // ast for `|__d| std::serialize::decode(__d)`
-        let expr_lambda = cx.lambda1(
-            cx.expr_blk(
-                cx.expr_call(
-                    span,
-                    cx.expr_path_global(span, ~[
-                        cx.ident_of("std"),
-                        cx.ident_of("serialize"),
-                        cx.ident_of("Decodable"),
-                        cx.ident_of("decode"),
-                    ]),
-                    ~[cx.expr_var(span, "__d")]
-                )
-            ),
-            cx.ident_of("__d")
-        );
-
-        // ast for `__d.read_struct_field($(name), $(idx), $(expr_lambda))`
-        let expr: @ast::expr = cx.expr_method_call(
-            span,
-            cx.expr_var(span, "__d"),
-            cx.ident_of("read_struct_field"),
-            ~[
-                cx.lit_str(span, @cx.str_of(field.ident)),
-                cx.lit_uint(span, idx),
-                expr_lambda,
-            ]
-        );
-
-        codemap::spanned {
-            node: ast::field_ {
-                mutbl: field.mutbl,
-                ident: field.ident,
-                expr: expr,
-            },
-            span: span,
-        }
-    };
-
-    // ast for `read_struct($(name), |__d| $(fields))`
-    let body = cx.expr_method_call(
-        span,
-        cx.expr_var(span, "__d"),
-        cx.ident_of("read_struct"),
-        ~[
-            cx.lit_str(span, @cx.str_of(ident)),
-            cx.lit_uint(span, fields.len()),
-            cx.lambda_expr_1(
-                cx.expr(
-                    span,
-                    ast::expr_struct(
-                        cx.path(span, ~[ident]),
-                        fields,
-                        None
-                    )
-                ),
-                cx.ident_of("__d")
-            ),
-        ]
-    );
-
-    mk_deser_impl(cx, span, ident, generics, body)
-}
-
-// Records and structs don't have the same fields types, but they share enough
-// that if we extract the right subfields out we can share the code
-// generator code.
-struct field {
-    span: span,
-    ident: ast::ident,
-    mutbl: ast::mutability,
-}
-
-fn mk_struct_fields(fields: &[@ast::struct_field]) -> ~[field] {
-    do fields.map |field| {
-        let ident = match field.node.kind {
-            ast::named_field(ident, _) => ident,
-            _ => fail!("[auto_encode] does not support unnamed fields")
-        };
-
-        field {
-            span: field.span,
-            ident: ident,
-            mutbl: ast::m_imm,
-        }
-    }
-}
-
-fn mk_enum_ser_impl(
-    cx: @ext_ctxt,
-    span: span,
-    ident: ast::ident,
-    enum_def: ast::enum_def,
-    generics: &ast::Generics
-) -> @ast::item {
-    let body = mk_enum_ser_body(
-        cx,
-        span,
-        ident,
-        copy enum_def.variants
-    );
-
-    mk_ser_impl(cx, span, ident, generics, body)
-}
-
-fn mk_enum_deser_impl(
-    cx: @ext_ctxt,
-    span: span,
-    ident: ast::ident,
-    enum_def: ast::enum_def,
-    generics: &ast::Generics
-) -> @ast::item {
-    let body = mk_enum_deser_body(
-        cx,
-        span,
-        ident,
-        enum_def.variants
-    );
-
-    mk_deser_impl(cx, span, ident, generics, body)
-}
-
-fn ser_variant(
-    cx: @ext_ctxt,
-    span: span,
-    v_name: ast::ident,
-    v_idx: uint,
-    args: ~[ast::variant_arg]
-) -> ast::arm {
-    // Name the variant arguments.
-    let names = args.mapi(|i, _arg| cx.ident_of(fmt!("__v%u", i)));
-
-    // Bind the names to the variant argument type.
-    let pats = args.mapi(|i, arg| cx.binder_pat(arg.ty.span, names[i]));
-
-    let pat_node = if pats.is_empty() {
-        ast::pat_ident(
-            ast::bind_infer,
-            cx.path(span, ~[v_name]),
-            None
-        )
-    } else {
-        ast::pat_enum(
-            cx.path(span, ~[v_name]),
-            Some(pats)
-        )
-    };
-
-    let pat = @ast::pat {
-        id: cx.next_id(),
-        node: pat_node,
-        span: span,
-    };
-
-    let stmts = do args.mapi |a_idx, _arg| {
-        // ast for `__s.emit_enum_variant_arg`
-        let expr_emit = cx.expr_field(
-            span,
-            cx.expr_var(span, "__s"),
-            cx.ident_of("emit_enum_variant_arg")
-        );
-
-        // ast for `|__s| $(v).encode(__s)`
-        let expr_encode = cx.lambda_expr_1(
-            cx.expr_method_call(
-                span,
-                 cx.expr_path(span, ~[names[a_idx]]),
-                 cx.ident_of("encode"),
-                ~[cx.expr_var(span, "__s")]
-            ),
-            cx.ident_of("__s")
-        );
-
-        // ast for `$(expr_emit)($(a_idx), $(expr_encode))`
-        cx.stmt(
-            cx.expr_call(
-                span,
-                expr_emit,
-                ~[cx.lit_uint(span, a_idx), expr_encode]
-            )
-        )
-    };
-
-    // ast for `__s.emit_enum_variant($(name), $(idx), $(sz), $(lambda))`
-    let body = cx.expr_method_call(
-        span,
-        cx.expr_var(span, "__s"),
-        cx.ident_of("emit_enum_variant"),
-        ~[
-            cx.lit_str(span, @cx.str_of(v_name)),
-            cx.lit_uint(span, v_idx),
-            cx.lit_uint(span, stmts.len()),
-            cx.lambda_stmts_1(span, stmts, cx.ident_of("__s")),
-        ]
-    );
-
-    ast::arm { pats: ~[pat], guard: None, body: cx.expr_blk(body) }
-}
-
-fn mk_enum_ser_body(
-    cx: @ext_ctxt,
-    span: span,
-    name: ast::ident,
-    variants: ~[ast::variant]
-) -> @ast::expr {
-    let arms = do variants.mapi |v_idx, variant| {
-        match variant.node.kind {
-            ast::tuple_variant_kind(ref args) =>
-                ser_variant(
-                    cx,
-                    span,
-                    variant.node.name,
-                    v_idx,
-                    /*bad*/ copy *args
-                ),
-            ast::struct_variant_kind(*) =>
-                fail!("struct variants unimplemented"),
-        }
-    };
-
-    // ast for `match *self { $(arms) }`
-    let match_expr = cx.expr(
-        span,
-        ast::expr_match(cx.expr(span,
-                                ast::expr_unary(ast::deref,
-                                                cx.expr_self(span))),
-                        arms)
-    );
-
-    // ast for `__s.emit_enum($(name), || $(match_expr))`
-    cx.expr_method_call(
-        span,
-        cx.expr_var(span, "__s"),
-        cx.ident_of("emit_enum"),
-        ~[
-            cx.lit_str(span, @cx.str_of(name)),
-            cx.lambda_expr_1(match_expr, cx.ident_of("__s")),
-        ]
-    )
-}
-
-fn mk_enum_deser_variant_nary(
-    cx: @ext_ctxt,
-    span: span,
-    name: ast::ident,
-    args: ~[ast::variant_arg]
-) -> @ast::expr {
-    let args = do args.mapi |idx, _arg| {
-        // ast for `|__s| std::serialize::decode(__d)`
-        let expr_lambda = cx.lambda_expr_1(
-            cx.expr_call(
-                span,
-                cx.expr_path_global(span, ~[
-                    cx.ident_of("std"),
-                    cx.ident_of("serialize"),
-                    cx.ident_of("Decodable"),
-                    cx.ident_of("decode"),
-                ]),
-                ~[cx.expr_var(span, "__d")]
-            ),
-            cx.ident_of("__d")
-        );
-
-        // ast for `__d.read_enum_variant_arg($(a_idx), $(expr_lambda))`
-        cx.expr_method_call(
-            span,
-            cx.expr_var(span, "__d"),
-            cx.ident_of("read_enum_variant_arg"),
-            ~[cx.lit_uint(span, idx), expr_lambda]
-        )
-    };
-
-    // ast for `$(name)($(args))`
-    cx.expr_call(span, cx.expr_path(span, ~[name]), args)
-}
-
-fn mk_enum_deser_body(
-    ext_cx: @ext_ctxt,
-    span: span,
-    name: ast::ident,
-    variants: &[ast::variant]
-) -> @ast::expr {
-    let expr_arm_names = build::mk_base_vec_e(
-        ext_cx,
-        span,
-         do variants.map |variant| {
-            build::mk_base_str(
-                ext_cx,
-                span,
-                ext_cx.str_of(variant.node.name)
-            )
-        }
-    );
-
-    let mut arms = do variants.mapi |v_idx, variant| {
-        let body = match variant.node.kind {
-            ast::tuple_variant_kind(ref args) => {
-                if args.is_empty() {
-                    // for a nullary variant v, do "v"
-                    ext_cx.expr_path(span, ~[variant.node.name])
-                } else {
-                    // for an n-ary variant v, do "v(a_1, ..., a_n)"
-                    mk_enum_deser_variant_nary(
-                        ext_cx,
-                        span,
-                        variant.node.name,
-                        copy *args
-                    )
-                }
-            },
-            ast::struct_variant_kind(*) =>
-                fail!("struct variants unimplemented"),
-        };
-
-        let pat = @ast::pat {
-            id: ext_cx.next_id(),
-            node: ast::pat_lit(ext_cx.lit_uint(span, v_idx)),
-            span: span,
-        };
-
-        ast::arm {
-            pats: ~[pat],
-            guard: None,
-            body: ext_cx.expr_blk(body),
-        }
-    };
-
-    let quoted_expr = copy quote_expr!(
-      ::core::sys::FailWithCause::fail_with("explicit failure", "empty", 1);
-    ).node;
-
-    let impossible_case = ast::arm {
-        pats: ~[@ast::pat {
-            id: ext_cx.next_id(),
-            node: ast::pat_wild,
-            span: span,
-        }],
-        guard: None,
-
-        // FIXME(#3198): proper error message
-        body: ext_cx.expr_blk(ext_cx.expr(span, quoted_expr)),
-    };
-
-    arms.push(impossible_case);
-
-    // ast for `|i| { match i { $(arms) } }`
-    let expr_lambda = ext_cx.expr(
-        span,
-        ast::expr_fn_block(
-            ast::fn_decl {
-                inputs: ~[
-                    ast::arg {
-                        is_mutbl: false,
-                        ty: @ast::Ty {
-                            id: ext_cx.next_id(),
-                            node: ast::ty_infer,
-                            span: span
-                        },
-                        pat: @ast::pat {
-                            id: ext_cx.next_id(),
-                            node: ast::pat_ident(
-                                ast::bind_by_copy,
-                                ast_util::ident_to_path(span,
-                                    ext_cx.ident_of("__d")),
-                                None),
-                            span: span,
-                        },
-                        id: ext_cx.next_id(),
-                    },
-                    ast::arg {
-                        is_mutbl: false,
-                        ty: @ast::Ty {
-                            id: ext_cx.next_id(),
-                            node: ast::ty_infer,
-                            span: span
-                        },
-                        pat: @ast::pat {
-                            id: ext_cx.next_id(),
-                            node: ast::pat_ident(
-                                ast::bind_by_copy,
-                                ast_util::ident_to_path(span,
-                                    ext_cx.ident_of("i")),
-                                None),
-                            span: span,
-                        },
-                        id: ext_cx.next_id(),
-                    }
-                ],
-                output: @ast::Ty {
-                    id: ext_cx.next_id(),
-                    node: ast::ty_infer,
-                    span: span,
-                },
-                cf: ast::return_val,
-            },
-            ext_cx.expr_blk(
-                ext_cx.expr(
-                    span,
-                    ast::expr_match(ext_cx.expr_var(span, "i"), arms)
-                )
-            )
-        )
-    );
-
-    // ast for `__d.read_enum_variant($expr_arm_names, $(expr_lambda))`
-    let expr_lambda = ext_cx.lambda_expr_1(
-        ext_cx.expr_method_call(
-            span,
-            ext_cx.expr_var(span, "__d"),
-            ext_cx.ident_of("read_enum_variant"),
-            ~[expr_arm_names, expr_lambda]
-        ),
-        ext_cx.ident_of("__d")
-    );
-
-    // ast for `__d.read_enum($(e_name), $(expr_lambda))`
-    ext_cx.expr_method_call(
-        span,
-        ext_cx.expr_var(span, "__d"),
-        ext_cx.ident_of("read_enum"),
-        ~[
-            ext_cx.lit_str(span, @ext_cx.str_of(name)),
-            expr_lambda
-        ]
-    )
-}
-
-#[cfg(test)]
-mod test {
-    use core::option::{None, Some};
-    use std::serialize::Encodable;
-    use std::serialize::Encoder;
-
-    // just adding the ones I want to test, for now:
-    #[deriving(Eq)]
-    pub enum call {
-        CallToEmitEnum(~str),
-        CallToEmitEnumVariant(~str, uint, uint),
-        CallToEmitEnumVariantArg(uint),
-        CallToEmitUint(uint),
-        CallToEmitNil,
-        CallToEmitStruct(~str,uint),
-        CallToEmitField(~str,uint),
-        CallToEmitOption,
-        CallToEmitOptionNone,
-        CallToEmitOptionSome,
-        // all of the ones I was too lazy to handle:
-        CallToOther
-    }
-    // using `@mut` rather than changing the
-    // type of self in every method of every encoder everywhere.
-    pub struct TestEncoder {call_log : @mut ~[call]}
-
-    pub impl TestEncoder {
-        // these self's should be &mut self's, as well....
-        fn add_to_log (&self, c : call) {
-            self.call_log.push(copy c);
-        }
-        fn add_unknown_to_log (&self) {
-            self.add_to_log (CallToOther)
-        }
-    }
-
-    impl Encoder for TestEncoder {
-        fn emit_nil(&mut self) { self.add_to_log(CallToEmitNil) }
-
-        fn emit_uint(&mut self, v: uint) {
-            self.add_to_log(CallToEmitUint(v));
-        }
-        fn emit_u64(&mut self, _v: u64) { self.add_unknown_to_log(); }
-        fn emit_u32(&mut self, _v: u32) { self.add_unknown_to_log(); }
-        fn emit_u16(&mut self, _v: u16) { self.add_unknown_to_log(); }
-        fn emit_u8(&mut self, _v: u8)   { self.add_unknown_to_log(); }
-
-        fn emit_int(&mut self, _v: int) { self.add_unknown_to_log(); }
-        fn emit_i64(&mut self, _v: i64) { self.add_unknown_to_log(); }
-        fn emit_i32(&mut self, _v: i32) { self.add_unknown_to_log(); }
-        fn emit_i16(&mut self, _v: i16) { self.add_unknown_to_log(); }
-        fn emit_i8(&mut self, _v: i8)   { self.add_unknown_to_log(); }
-
-        fn emit_bool(&mut self, _v: bool) { self.add_unknown_to_log(); }
-
-        fn emit_f64(&mut self, _v: f64) { self.add_unknown_to_log(); }
-        fn emit_f32(&mut self, _v: f32) { self.add_unknown_to_log(); }
-        fn emit_float(&mut self, _v: float) { self.add_unknown_to_log(); }
-
-        fn emit_char(&mut self, _v: char) { self.add_unknown_to_log(); }
-        fn emit_str(&mut self, _v: &str) { self.add_unknown_to_log(); }
-
-        fn emit_enum(&mut self, name: &str, f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitEnum(name.to_str()));
-            f(self);
-        }
-
-        fn emit_enum_variant(&mut self,
-                             name: &str,
-                             id: uint,
-                             cnt: uint,
-                             f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitEnumVariant(name.to_str(), id, cnt));
-            f(self);
-        }
-
-        fn emit_enum_variant_arg(&mut self,
-                                 idx: uint,
-                                 f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitEnumVariantArg(idx));
-            f(self);
-        }
-
-        fn emit_enum_struct_variant(&mut self,
-                                    name: &str,
-                                    id: uint,
-                                    cnt: uint,
-                                    f: &fn(&mut TestEncoder)) {
-            self.emit_enum_variant(name, id, cnt, f)
-        }
-
-        fn emit_enum_struct_variant_field(&mut self,
-                                          _name: &str,
-                                          idx: uint,
-                                          f: &fn(&mut TestEncoder)) {
-            self.emit_enum_variant_arg(idx, f)
-        }
-
-        fn emit_struct(&mut self,
-                       name: &str,
-                       len: uint,
-                       f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitStruct (name.to_str(),len));
-            f(self);
-        }
-        fn emit_struct_field(&mut self,
-                             name: &str,
-                             idx: uint,
-                             f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitField (name.to_str(),idx));
-            f(self);
-        }
-
-        fn emit_tuple(&mut self, _len: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-        fn emit_tuple_arg(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-
-        fn emit_tuple_struct(&mut self,
-                             _name: &str,
-                             _len: uint,
-                             f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-
-        fn emit_tuple_struct_arg(&mut self,
-                                 _idx: uint,
-                                 f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-
-        fn emit_option(&mut self, f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitOption);
-            f(self);
-        }
-        fn emit_option_none(&mut self) {
-            self.add_to_log(CallToEmitOptionNone);
-        }
-        fn emit_option_some(&mut self, f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitOptionSome);
-            f(self);
-        }
-
-        fn emit_seq(&mut self, _len: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-        fn emit_seq_elt(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-
-        fn emit_map(&mut self, _len: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-        fn emit_map_elt_key(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-        fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-    }
-
-
-    fn to_call_log<E:Encodable<TestEncoder>>(val: E) -> ~[call] {
-        let mut te = TestEncoder {
-            call_log: @mut ~[]
-        };
-        val.encode(&mut te);
-        copy *te.call_log
-    }
-
-    #[auto_encode]
-    enum Written {
-        Book(uint,uint),
-        Magazine(~str)
-    }
-
-    #[test]
-    fn test_encode_enum() {
-        assert_eq!(
-            to_call_log(Book(34,44)),
-            ~[
-                CallToEmitEnum(~"Written"),
-                CallToEmitEnumVariant(~"Book",0,2),
-                CallToEmitEnumVariantArg(0),
-                CallToEmitUint(34),
-                CallToEmitEnumVariantArg(1),
-                CallToEmitUint(44),
-            ]
-        );
-    }
-
-    pub struct BPos(uint);
-
-    #[auto_encode]
-    pub struct HasPos { pos : BPos }
-
-    #[test]
-    fn test_encode_newtype() {
-        assert_eq!(
-            to_call_log(HasPos { pos:BPos(48) }),
-            ~[
-                CallToEmitStruct(~"HasPos",1),
-                CallToEmitField(~"pos",0),
-                CallToEmitUint(48),
-            ]
-        );
-    }
-
-    #[test]
-    fn test_encode_option() {
-        let mut v = None;
-
-        assert_eq!(
-            to_call_log(v),
-            ~[
-                CallToEmitOption,
-                CallToEmitOptionNone,
-            ]
-        );
-
-        v = Some(54u);
-        assert_eq!(
-            to_call_log(v),
-            ~[
-                CallToEmitOption,
-                CallToEmitOptionSome,
-                CallToEmitUint(54)
-            ]
-        );
-    }
+    cx.span_err(span, "`#[auto_decode]` is deprecated, use `#[deriving(Decodable)]` instead");
+    in_items
 }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 30470d2ebe7..a97c69ba4ff 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -139,6 +139,8 @@ pub fn syntax_expander_table() -> SyntaxEnv {
         @SE(ItemDecorator(ext::auto_encode::expand_auto_decode)));
     syntax_expanders.insert(@~"env",
                             builtin_normal_tt(ext::env::expand_syntax_ext));
+    syntax_expanders.insert(@~"bytes",
+                            builtin_normal_tt(ext::bytes::expand_syntax_ext));
     syntax_expanders.insert(@~"concat_idents",
                             builtin_normal_tt(
                                 ext::concat_idents::expand_syntax_ext));
@@ -148,15 +150,6 @@ pub fn syntax_expander_table() -> SyntaxEnv {
     syntax_expanders.insert(@~"deriving",
                             @SE(ItemDecorator(
                                 ext::deriving::expand_meta_deriving)));
-    syntax_expanders.insert(@~"deriving_eq",
-                            @SE(ItemDecorator(
-                                ext::deriving::eq::expand_deriving_obsolete)));
-    syntax_expanders.insert(@~"deriving_iter_bytes",
-                            @SE(ItemDecorator(
-                                ext::deriving::iter_bytes::expand_deriving_obsolete)));
-    syntax_expanders.insert(@~"deriving_clone",
-                            @SE(ItemDecorator(
-                                ext::deriving::clone::expand_deriving_obsolete)));
 
     // Quasi-quoting expanders
     syntax_expanders.insert(@~"quote_tokens",
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 605ba65b51a..624e0495e59 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -196,6 +196,7 @@ pub fn mk_global_struct_e(cx: @ext_ctxt,
 }
 pub fn mk_glob_use(cx: @ext_ctxt,
                    sp: span,
+                   vis: ast::visibility,
                    path: ~[ast::ident]) -> @ast::view_item {
     let glob = @codemap::spanned {
         node: ast::view_path_glob(mk_raw_path(sp, path), cx.next_id()),
@@ -203,7 +204,7 @@ pub fn mk_glob_use(cx: @ext_ctxt,
     };
     @ast::view_item { node: ast::view_item_use(~[glob]),
                       attrs: ~[],
-                      vis: ast::private,
+                      vis: vis,
                       span: sp }
 }
 pub fn mk_local(cx: @ext_ctxt, sp: span, mutbl: bool,
@@ -538,3 +539,301 @@ pub fn duplicate_expr(cx: @ext_ctxt, expr: @ast::expr) -> @ast::expr {
     folder.fold_expr(expr)
 }
 
+
+
+// Transitional reexports so qquote can find the paths it is looking for
+mod syntax {
+    pub use ext;
+    pub use parse;
+}
+
+trait ExtCtxtMethods {
+    fn bind_path(&self,
+                 span: span,
+                 ident: ast::ident,
+                 path: @ast::Path,
+                 bounds: @OptVec<ast::TyParamBound>)
+                 -> ast::TyParam;
+    fn expr(&self, span: span, node: ast::expr_) -> @ast::expr;
+    fn path(&self, span: span, strs: ~[ast::ident]) -> @ast::Path;
+    fn path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::Path;
+    fn path_tps(&self, span: span, strs: ~[ast::ident], tps: ~[@ast::Ty])
+                -> @ast::Path;
+    fn path_tps_global(&self,
+                       span: span,
+                       strs: ~[ast::ident],
+                       tps: ~[@ast::Ty])
+                       -> @ast::Path;
+    fn ty_path(&self, span: span, strs: ~[ast::ident], tps: ~[@ast::Ty])
+               -> @ast::Ty;
+    fn binder_pat(&self, span: span, nm: ast::ident) -> @ast::pat;
+    fn stmt(&self, expr: @ast::expr) -> @ast::stmt;
+    fn lit_str(&self, span: span, s: @~str) -> @ast::expr;
+    fn lit_uint(&self, span: span, i: uint) -> @ast::expr;
+    fn lambda0(&self, blk: ast::blk) -> @ast::expr;
+    fn lambda1(&self, blk: ast::blk, ident: ast::ident) -> @ast::expr;
+    fn blk(&self, span: span, stmts: ~[@ast::stmt]) -> ast::blk;
+    fn expr_blk(&self, expr: @ast::expr) -> ast::blk;
+    fn expr_path(&self, span: span, strs: ~[ast::ident]) -> @ast::expr;
+    fn expr_path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::expr;
+    fn expr_var(&self, span: span, var: &str) -> @ast::expr;
+    fn expr_self(&self, span: span) -> @ast::expr;
+    fn expr_field(&self, span: span, expr: @ast::expr, ident: ast::ident)
+                  -> @ast::expr;
+    fn expr_call(&self, span: span, expr: @ast::expr, args: ~[@ast::expr])
+                 -> @ast::expr;
+    fn expr_method_call(&self,
+                        span: span,
+                        expr: @ast::expr,
+                        ident: ast::ident,
+                        args: ~[@ast::expr])
+                        -> @ast::expr;
+    fn lambda_expr_0(&self, expr: @ast::expr) -> @ast::expr;
+    fn lambda_expr_1(&self, expr: @ast::expr, ident: ast::ident)
+                    -> @ast::expr;
+    fn lambda_stmts_0(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr;
+    fn lambda_stmts_1(&self,
+                      span: span,
+                      stmts: ~[@ast::stmt],
+                      ident: ast::ident)
+                      -> @ast::expr;
+}
+
+impl ExtCtxtMethods for @ext_ctxt {
+    fn bind_path(
+        &self,
+        _span: span,
+        ident: ast::ident,
+        path: @ast::Path,
+        bounds: @OptVec<ast::TyParamBound>
+    ) -> ast::TyParam {
+        let bound = ast::TraitTyParamBound(@ast::trait_ref {
+            ref_id: self.next_id(),
+            path: path
+        });
+
+        ast::TyParam {
+            ident: ident,
+            id: self.next_id(),
+            bounds: @bounds.prepend(bound)
+        }
+    }
+
+    fn expr(&self, span: span, node: ast::expr_) -> @ast::expr {
+        @ast::expr {
+            id: self.next_id(),
+            callee_id: self.next_id(),
+            node: node,
+            span: span,
+        }
+    }
+
+    fn path(&self, span: span, strs: ~[ast::ident]) -> @ast::Path {
+        @ast::Path {
+            span: span,
+            global: false,
+            idents: strs,
+            rp: None,
+            types: ~[]
+        }
+    }
+
+    fn path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::Path {
+        @ast::Path {
+            span: span,
+            global: true,
+            idents: strs,
+            rp: None,
+            types: ~[]
+        }
+    }
+
+    fn path_tps(
+        &self,
+        span: span,
+        strs: ~[ast::ident],
+        tps: ~[@ast::Ty]
+    ) -> @ast::Path {
+        @ast::Path {
+            span: span,
+            global: false,
+            idents: strs,
+            rp: None,
+            types: tps
+        }
+    }
+
+    fn path_tps_global(
+        &self,
+        span: span,
+        strs: ~[ast::ident],
+        tps: ~[@ast::Ty]
+    ) -> @ast::Path {
+        @ast::Path {
+            span: span,
+            global: true,
+            idents: strs,
+            rp: None,
+            types: tps
+        }
+    }
+
+    fn ty_path(
+        &self,
+        span: span,
+        strs: ~[ast::ident],
+        tps: ~[@ast::Ty]
+    ) -> @ast::Ty {
+        @ast::Ty {
+            id: self.next_id(),
+            node: ast::ty_path(
+                self.path_tps(span, strs, tps),
+                self.next_id()),
+            span: span,
+        }
+    }
+
+    fn binder_pat(&self, span: span, nm: ast::ident) -> @ast::pat {
+        @ast::pat {
+            id: self.next_id(),
+            node: ast::pat_ident(
+                ast::bind_by_ref(ast::m_imm),
+                self.path(span, ~[nm]),
+                None),
+            span: span,
+        }
+    }
+
+    fn stmt(&self, expr: @ast::expr) -> @ast::stmt {
+        @codemap::spanned { node: ast::stmt_semi(expr, self.next_id()),
+                       span: expr.span }
+    }
+
+    fn lit_str(&self, span: span, s: @~str) -> @ast::expr {
+        self.expr(
+            span,
+            ast::expr_vstore(
+                self.expr(
+                    span,
+                    ast::expr_lit(
+                        @codemap::spanned { node: ast::lit_str(s),
+                                        span: span})),
+                ast::expr_vstore_uniq))
+    }
+
+    fn lit_uint(&self, span: span, i: uint) -> @ast::expr {
+        self.expr(
+            span,
+            ast::expr_lit(
+                @codemap::spanned { node: ast::lit_uint(i as u64, ast::ty_u),
+                                span: span}))
+    }
+
+    fn lambda0(&self, blk: ast::blk) -> @ast::expr {
+        let ext_cx = *self;
+        let blk_e = self.expr(copy blk.span, ast::expr_block(copy blk));
+        quote_expr!( || $blk_e )
+    }
+
+    fn lambda1(&self, blk: ast::blk, ident: ast::ident) -> @ast::expr {
+        let ext_cx = *self;
+        let blk_e = self.expr(copy blk.span, ast::expr_block(copy blk));
+        quote_expr!( |$ident| $blk_e )
+    }
+
+    fn blk(&self, span: span, stmts: ~[@ast::stmt]) -> ast::blk {
+        codemap::spanned {
+            node: ast::blk_ {
+                view_items: ~[],
+                stmts: stmts,
+                expr: None,
+                id: self.next_id(),
+                rules: ast::default_blk,
+            },
+            span: span,
+        }
+    }
+
+    fn expr_blk(&self, expr: @ast::expr) -> ast::blk {
+        codemap::spanned {
+            node: ast::blk_ {
+                view_items: ~[],
+                stmts: ~[],
+                expr: Some(expr),
+                id: self.next_id(),
+                rules: ast::default_blk,
+            },
+            span: expr.span,
+        }
+    }
+
+    fn expr_path(&self, span: span, strs: ~[ast::ident]) -> @ast::expr {
+        self.expr(span, ast::expr_path(self.path(span, strs)))
+    }
+
+    fn expr_path_global(
+        &self,
+        span: span,
+        strs: ~[ast::ident]
+    ) -> @ast::expr {
+        self.expr(span, ast::expr_path(self.path_global(span, strs)))
+    }
+
+    fn expr_var(&self, span: span, var: &str) -> @ast::expr {
+        self.expr_path(span, ~[self.ident_of(var)])
+    }
+
+    fn expr_self(&self, span: span) -> @ast::expr {
+        self.expr(span, ast::expr_self)
+    }
+
+    fn expr_field(
+        &self,
+        span: span,
+        expr: @ast::expr,
+        ident: ast::ident
+    ) -> @ast::expr {
+        self.expr(span, ast::expr_field(expr, ident, ~[]))
+    }
+
+    fn expr_call(
+        &self,
+        span: span,
+        expr: @ast::expr,
+        args: ~[@ast::expr]
+    ) -> @ast::expr {
+        self.expr(span, ast::expr_call(expr, args, ast::NoSugar))
+    }
+
+    fn expr_method_call(
+        &self,
+        span: span,
+        expr: @ast::expr,
+        ident: ast::ident,
+        args: ~[@ast::expr]
+    ) -> @ast::expr {
+        self.expr(span,
+                  ast::expr_method_call(expr, ident, ~[], args, ast::NoSugar))
+    }
+
+    fn lambda_expr_0(&self, expr: @ast::expr) -> @ast::expr {
+        self.lambda0(self.expr_blk(expr))
+    }
+
+    fn lambda_expr_1(&self, expr: @ast::expr, ident: ast::ident)
+                    -> @ast::expr {
+        self.lambda1(self.expr_blk(expr), ident)
+    }
+
+    fn lambda_stmts_0(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr {
+        self.lambda0(self.blk(span, stmts))
+    }
+
+    fn lambda_stmts_1(&self,
+                      span: span,
+                      stmts: ~[@ast::stmt],
+                      ident: ast::ident)
+                      -> @ast::expr {
+        self.lambda1(self.blk(span, stmts), ident)
+    }
+}
diff --git a/src/libsyntax/ext/bytes.rs b/src/libsyntax/ext/bytes.rs
new file mode 100644
index 00000000000..7c2f27ada3b
--- /dev/null
+++ b/src/libsyntax/ext/bytes.rs
@@ -0,0 +1,73 @@
+// Copyright 2013 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.
+
+/* The compiler code necessary to support the bytes! extension. */
+
+use ast;
+use codemap::span;
+use ext::base::*;
+use ext::base;
+use ext::build::{mk_u8, mk_slice_vec_e};
+
+pub fn expand_syntax_ext(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) -> base::MacResult {
+    // Gather all argument expressions
+    let exprs = get_exprs_from_tts(cx, tts);
+    let mut bytes = ~[];
+
+    for exprs.each |expr| {
+        match expr.node {
+            // expression is a literal
+            ast::expr_lit(lit) => match lit.node {
+                // string literal, push each byte to vector expression
+                ast::lit_str(s) => {
+                    for s.each |byte| {
+                        bytes.push(mk_u8(cx, sp, byte));
+                    }
+                }
+
+                // u8 literal, push to vector expression
+                ast::lit_uint(v, ast::ty_u8) => {
+                    if v > 0xFF {
+                        cx.span_err(sp, "Too large u8 literal in bytes!")
+                    } else {
+                        bytes.push(mk_u8(cx, sp, v as u8));
+                    }
+                }
+
+                // integer literal, push to vector expression
+                ast::lit_int_unsuffixed(v) => {
+                    if v > 0xFF {
+                        cx.span_err(sp, "Too large integer literal in bytes!")
+                    } else if v < 0 {
+                        cx.span_err(sp, "Negative integer literal in bytes!")
+                    } else {
+                        bytes.push(mk_u8(cx, sp, v as u8));
+                    }
+                }
+
+                // char literal, push to vector expression
+                ast::lit_int(v, ast::ty_char) => {
+                    if (v as char).is_ascii() {
+                        bytes.push(mk_u8(cx, sp, v as u8));
+                    } else {
+                        cx.span_err(sp, "Non-ascii char literal in bytes!")
+                    }
+                }
+
+                _ => cx.span_err(sp, "Unsupported literal in bytes!")
+            },
+
+            _ => cx.span_err(sp, "Non-literal in bytes!")
+        }
+    }
+
+    let e = mk_slice_vec_e(cx, sp, bytes);
+    MRExpr(e)
+}
diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs
index 1a45107c267..aceb60ebbd7 100644
--- a/src/libsyntax/ext/deriving/clone.rs
+++ b/src/libsyntax/ext/deriving/clone.rs
@@ -32,7 +32,7 @@ pub fn expand_deriving_clone(cx: @ext_ctxt,
                 args: ~[],
                 ret_ty: Self,
                 const_nonmatching: false,
-                combine_substructure: cs_clone
+                combine_substructure: |c, s, sub| cs_clone("Clone", c, s, sub)
             }
         ]
     };
@@ -42,17 +42,39 @@ pub fn expand_deriving_clone(cx: @ext_ctxt,
                             &trait_def)
 }
 
-pub fn expand_deriving_obsolete(cx: @ext_ctxt,
-                                span: span,
-                                _mitem: @meta_item,
-                                in_items: ~[@item])
-                             -> ~[@item] {
-    cx.span_err(span, ~"`#[deriving_clone]` is obsolete; use `#[deriving(Clone)]` instead");
-    in_items
+pub fn expand_deriving_deep_clone(cx: @ext_ctxt,
+                                 span: span,
+                                 mitem: @meta_item,
+                                 in_items: ~[@item])
+    -> ~[@item] {
+    let trait_def = TraitDef {
+        path: Path::new(~[~"core", ~"clone", ~"DeepClone"]),
+        additional_bounds: ~[],
+        generics: LifetimeBounds::empty(),
+        methods: ~[
+            MethodDef {
+                name: ~"deep_clone",
+                generics: LifetimeBounds::empty(),
+                explicit_self: borrowed_explicit_self(),
+                args: ~[],
+                ret_ty: Self,
+                const_nonmatching: false,
+                // cs_clone uses the ident passed to it, i.e. it will
+                // call deep_clone (not clone) here.
+                combine_substructure: |c, s, sub| cs_clone("DeepClone", c, s, sub)
+            }
+        ]
+    };
+
+    expand_deriving_generic(cx, span,
+                            mitem, in_items,
+                            &trait_def)
 }
 
-fn cs_clone(cx: @ext_ctxt, span: span,
-            substr: &Substructure) -> @expr {
+fn cs_clone(
+    name: &str,
+    cx: @ext_ctxt, span: span,
+    substr: &Substructure) -> @expr {
     let clone_ident = substr.method_ident;
     let ctor_ident;
     let all_fields;
@@ -68,8 +90,12 @@ fn cs_clone(cx: @ext_ctxt, span: span,
             ctor_ident = ~[ variant.node.name ];
             all_fields = af;
         },
-        EnumNonMatching(*) => cx.span_bug(span, "Non-matching enum variants in `deriving(Clone)`"),
-        StaticEnum(*) | StaticStruct(*) => cx.span_bug(span, "Static method in `deriving(Clone)`")
+        EnumNonMatching(*) => cx.span_bug(span,
+                                          fmt!("Non-matching enum variants in `deriving(%s)`",
+                                               name)),
+        StaticEnum(*) | StaticStruct(*) => cx.span_bug(span,
+                                                       fmt!("Static method in `deriving(%s)`",
+                                                            name))
     }
 
     match *all_fields {
@@ -84,8 +110,8 @@ fn cs_clone(cx: @ext_ctxt, span: span,
                 let ident = match o_id {
                     Some(i) => i,
                     None => cx.span_bug(span,
-                                        ~"unnamed field in normal struct \
-                                          in `deriving(Clone)`")
+                                        fmt!("unnamed field in normal struct in `deriving(%s)`",
+                                             name))
                 };
                 build::Field { ident: ident, ex: subcall(self_f) }
             };
diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs
index 7fc2fdc7963..3d93f844ea3 100644
--- a/src/libsyntax/ext/deriving/cmp/eq.rs
+++ b/src/libsyntax/ext/deriving/cmp/eq.rs
@@ -56,11 +56,3 @@ pub fn expand_deriving_eq(cx: @ext_ctxt,
     expand_deriving_generic(cx, span, mitem, in_items,
                             &trait_def)
 }
-
-pub fn expand_deriving_obsolete(cx: @ext_ctxt,
-                                span: span,
-                                _mitem: @meta_item,
-                                in_items: ~[@item]) -> ~[@item] {
-    cx.span_err(span, ~"`#[deriving_eq]` is obsolete; use `#[deriving(Eq)]` instead");
-    in_items
-}
diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs
index 3be65ecd8db..2e2f382a768 100644
--- a/src/libsyntax/ext/deriving/decodable.rs
+++ b/src/libsyntax/ext/deriving/decodable.rs
@@ -8,6 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+/*!
+The compiler code necessary for #[deriving(Decodable)]. See
+encodable.rs for more.
+*/
+
 use ast;
 use ast::*;
 use ext::base::ext_ctxt;
diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs
index 2078ec9d45c..8a1c3933f51 100644
--- a/src/libsyntax/ext/deriving/encodable.rs
+++ b/src/libsyntax/ext/deriving/encodable.rs
@@ -8,6 +8,74 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+/*!
+
+The compiler code necessary to implement the #[deriving(Encodable)]
+(and Decodable, in decodable.rs) extension.  The idea here is that
+type-defining items may be tagged with #[deriving(Encodable,
+Decodable)].
+
+For example, a type like:
+
+    #[deriving(Encodable, Decodable)]
+    struct Node {id: uint}
+
+would generate two implementations like:
+
+impl<S:std::serialize::Encoder> Encodable<S> for Node {
+    fn encode(&self, s: &S) {
+        do s.emit_struct("Node", 1) {
+            s.emit_field("id", 0, || s.emit_uint(self.id))
+        }
+    }
+}
+
+impl<D:Decoder> Decodable for node_id {
+    fn decode(d: &D) -> Node {
+        do d.read_struct("Node", 1) {
+            Node {
+                id: d.read_field(~"x", 0, || decode(d))
+            }
+        }
+    }
+}
+
+Other interesting scenarios are whe the item has type parameters or
+references other non-built-in types.  A type definition like:
+
+    #[deriving(Encodable, Decodable)]
+    struct spanned<T> {node: T, span: span}
+
+would yield functions like:
+
+    impl<
+        S: Encoder,
+        T: Encodable<S>
+    > spanned<T>: Encodable<S> {
+        fn encode<S:Encoder>(s: &S) {
+            do s.emit_rec {
+                s.emit_field("node", 0, || self.node.encode(s));
+                s.emit_field("span", 1, || self.span.encode(s));
+            }
+        }
+    }
+
+    impl<
+        D: Decoder,
+        T: Decodable<D>
+    > spanned<T>: Decodable<D> {
+        fn decode(d: &D) -> spanned<T> {
+            do d.read_rec {
+                {
+                    node: d.read_field(~"node", 0, || decode(d)),
+                    span: d.read_field(~"span", 1, || decode(d)),
+                }
+            }
+        }
+    }
+*/
+
+
 use ast;
 use ast::*;
 use ext::base::ext_ctxt;
@@ -403,3 +471,247 @@ fn expand_deriving_encodable_enum_method(
     // Create the method.
     create_encode_method(cx, span, ~[stmt])
 }
+
+#[cfg(test)]
+mod test {
+    extern mod std;
+    use core::option::{None, Some};
+    use std::serialize::Encodable;
+    use std::serialize::Encoder;
+
+    // just adding the ones I want to test, for now:
+    #[deriving(Eq)]
+    pub enum call {
+        CallToEmitEnum(~str),
+        CallToEmitEnumVariant(~str, uint, uint),
+        CallToEmitEnumVariantArg(uint),
+        CallToEmitUint(uint),
+        CallToEmitNil,
+        CallToEmitStruct(~str,uint),
+        CallToEmitField(~str,uint),
+        CallToEmitOption,
+        CallToEmitOptionNone,
+        CallToEmitOptionSome,
+        // all of the ones I was too lazy to handle:
+        CallToOther
+    }
+    // using `@mut` rather than changing the
+    // type of self in every method of every encoder everywhere.
+    pub struct TestEncoder {call_log : @mut ~[call]}
+
+    pub impl TestEncoder {
+        // these self's should be &mut self's, as well....
+        fn add_to_log (&self, c : call) {
+            self.call_log.push(copy c);
+        }
+        fn add_unknown_to_log (&self) {
+            self.add_to_log (CallToOther)
+        }
+    }
+
+    impl Encoder for TestEncoder {
+        fn emit_nil(&mut self) { self.add_to_log(CallToEmitNil) }
+
+        fn emit_uint(&mut self, v: uint) {
+            self.add_to_log(CallToEmitUint(v));
+        }
+        fn emit_u64(&mut self, _v: u64) { self.add_unknown_to_log(); }
+        fn emit_u32(&mut self, _v: u32) { self.add_unknown_to_log(); }
+        fn emit_u16(&mut self, _v: u16) { self.add_unknown_to_log(); }
+        fn emit_u8(&mut self, _v: u8)   { self.add_unknown_to_log(); }
+
+        fn emit_int(&mut self, _v: int) { self.add_unknown_to_log(); }
+        fn emit_i64(&mut self, _v: i64) { self.add_unknown_to_log(); }
+        fn emit_i32(&mut self, _v: i32) { self.add_unknown_to_log(); }
+        fn emit_i16(&mut self, _v: i16) { self.add_unknown_to_log(); }
+        fn emit_i8(&mut self, _v: i8)   { self.add_unknown_to_log(); }
+
+        fn emit_bool(&mut self, _v: bool) { self.add_unknown_to_log(); }
+
+        fn emit_f64(&mut self, _v: f64) { self.add_unknown_to_log(); }
+        fn emit_f32(&mut self, _v: f32) { self.add_unknown_to_log(); }
+        fn emit_float(&mut self, _v: float) { self.add_unknown_to_log(); }
+
+        fn emit_char(&mut self, _v: char) { self.add_unknown_to_log(); }
+        fn emit_str(&mut self, _v: &str) { self.add_unknown_to_log(); }
+
+        fn emit_enum(&mut self, name: &str, f: &fn(&mut TestEncoder)) {
+            self.add_to_log(CallToEmitEnum(name.to_str()));
+            f(self);
+        }
+
+        fn emit_enum_variant(&mut self,
+                             name: &str,
+                             id: uint,
+                             cnt: uint,
+                             f: &fn(&mut TestEncoder)) {
+            self.add_to_log(CallToEmitEnumVariant(name.to_str(), id, cnt));
+            f(self);
+        }
+
+        fn emit_enum_variant_arg(&mut self,
+                                 idx: uint,
+                                 f: &fn(&mut TestEncoder)) {
+            self.add_to_log(CallToEmitEnumVariantArg(idx));
+            f(self);
+        }
+
+        fn emit_enum_struct_variant(&mut self,
+                                    name: &str,
+                                    id: uint,
+                                    cnt: uint,
+                                    f: &fn(&mut TestEncoder)) {
+            self.emit_enum_variant(name, id, cnt, f)
+        }
+
+        fn emit_enum_struct_variant_field(&mut self,
+                                          _name: &str,
+                                          idx: uint,
+                                          f: &fn(&mut TestEncoder)) {
+            self.emit_enum_variant_arg(idx, f)
+        }
+
+        fn emit_struct(&mut self,
+                       name: &str,
+                       len: uint,
+                       f: &fn(&mut TestEncoder)) {
+            self.add_to_log(CallToEmitStruct (name.to_str(),len));
+            f(self);
+        }
+        fn emit_struct_field(&mut self,
+                             name: &str,
+                             idx: uint,
+                             f: &fn(&mut TestEncoder)) {
+            self.add_to_log(CallToEmitField (name.to_str(),idx));
+            f(self);
+        }
+
+        fn emit_tuple(&mut self, _len: uint, f: &fn(&mut TestEncoder)) {
+            self.add_unknown_to_log();
+            f(self);
+        }
+        fn emit_tuple_arg(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) {
+            self.add_unknown_to_log();
+            f(self);
+        }
+
+        fn emit_tuple_struct(&mut self,
+                             _name: &str,
+                             _len: uint,
+                             f: &fn(&mut TestEncoder)) {
+            self.add_unknown_to_log();
+            f(self);
+        }
+
+        fn emit_tuple_struct_arg(&mut self,
+                                 _idx: uint,
+                                 f: &fn(&mut TestEncoder)) {
+            self.add_unknown_to_log();
+            f(self);
+        }
+
+        fn emit_option(&mut self, f: &fn(&mut TestEncoder)) {
+            self.add_to_log(CallToEmitOption);
+            f(self);
+        }
+        fn emit_option_none(&mut self) {
+            self.add_to_log(CallToEmitOptionNone);
+        }
+        fn emit_option_some(&mut self, f: &fn(&mut TestEncoder)) {
+            self.add_to_log(CallToEmitOptionSome);
+            f(self);
+        }
+
+        fn emit_seq(&mut self, _len: uint, f: &fn(&mut TestEncoder)) {
+            self.add_unknown_to_log();
+            f(self);
+        }
+        fn emit_seq_elt(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) {
+            self.add_unknown_to_log();
+            f(self);
+        }
+
+        fn emit_map(&mut self, _len: uint, f: &fn(&mut TestEncoder)) {
+            self.add_unknown_to_log();
+            f(self);
+        }
+        fn emit_map_elt_key(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) {
+            self.add_unknown_to_log();
+            f(self);
+        }
+        fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) {
+            self.add_unknown_to_log();
+            f(self);
+        }
+    }
+
+
+    fn to_call_log<E:Encodable<TestEncoder>>(val: E) -> ~[call] {
+        let mut te = TestEncoder {
+            call_log: @mut ~[]
+        };
+        val.encode(&mut te);
+        copy *te.call_log
+    }
+
+    #[deriving(Encodable)]
+    enum Written {
+        Book(uint,uint),
+        Magazine(~str)
+    }
+
+    #[test]
+    fn test_encode_enum() {
+        assert_eq!(
+            to_call_log(Book(34,44)),
+            ~[
+                CallToEmitEnum(~"Written"),
+                CallToEmitEnumVariant(~"Book",0,2),
+                CallToEmitEnumVariantArg(0),
+                CallToEmitUint(34),
+                CallToEmitEnumVariantArg(1),
+                CallToEmitUint(44),
+            ]
+        );
+    }
+
+    pub struct BPos(uint);
+
+    #[deriving(Encodable)]
+    pub struct HasPos { pos : BPos }
+
+    #[test]
+    fn test_encode_newtype() {
+        assert_eq!(
+            to_call_log(HasPos { pos:BPos(48) }),
+            ~[
+                CallToEmitStruct(~"HasPos",1),
+                CallToEmitField(~"pos",0),
+                CallToEmitUint(48),
+            ]
+        );
+    }
+
+    #[test]
+    fn test_encode_option() {
+        let mut v = None;
+
+        assert_eq!(
+            to_call_log(v),
+            ~[
+                CallToEmitOption,
+                CallToEmitOptionNone,
+            ]
+        );
+
+        v = Some(54u);
+        assert_eq!(
+            to_call_log(v),
+            ~[
+                CallToEmitOption,
+                CallToEmitOptionSome,
+                CallToEmitUint(54)
+            ]
+        );
+    }
+}
diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs
index 27e3a54add5..1c9ec6ece2e 100644
--- a/src/libsyntax/ext/deriving/iter_bytes.rs
+++ b/src/libsyntax/ext/deriving/iter_bytes.rs
@@ -41,16 +41,6 @@ pub fn expand_deriving_iter_bytes(cx: @ext_ctxt,
     expand_deriving_generic(cx, span, mitem, in_items, &trait_def)
 }
 
-pub fn expand_deriving_obsolete(cx: @ext_ctxt,
-                                span: span,
-                                _mitem: @meta_item,
-                                in_items: ~[@item])
-                             -> ~[@item] {
-    cx.span_err(span, ~"`#[deriving_iter_bytes]` is obsolete; use `#[deriving(IterBytes)]` \
-                        instead");
-    in_items
-}
-
 fn iter_bytes_substructure(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
     let lsb0_f = match substr.nonself_args {
         [l, f] => ~[l, f],
diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs
index ba1f4e3ebb2..78cd5cdb423 100644
--- a/src/libsyntax/ext/deriving/mod.rs
+++ b/src/libsyntax/ext/deriving/mod.rs
@@ -8,8 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-/// The compiler code necessary to implement the #[deriving(Eq)] and
-/// #[deriving(IterBytes)] extensions.
+/*!
+The compiler code necessary to implement the #[deriving] extensions.
+
+
+FIXME (#2810)--Hygiene. Search for "__" strings (in other files too).
+We also assume "std" is the standard library, and "core" is the core
+library.
+
+*/
 
 use ast;
 use ast::{Ty, enum_def, expr, ident, item, Generics, meta_item, struct_def};
@@ -77,6 +84,7 @@ pub fn expand_meta_deriving(cx: @ext_ctxt,
                                                                    titem, in_items)));
                         match *tname {
                             ~"Clone" => expand!(clone::expand_deriving_clone),
+                            ~"DeepClone" => expand!(clone::expand_deriving_deep_clone),
 
                             ~"IterBytes" => expand!(iter_bytes::expand_deriving_iter_bytes),
 
@@ -203,8 +211,6 @@ pub fn create_derived_impl(cx: @ext_ctxt,
      *
      * where B1, B2, ... are the bounds given by `bounds_paths`.
      *
-     * FIXME(#5090): Remove code duplication between this and the
-     * code in auto_encode.rs
      */
 
     // Copy the lifetimes
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index f4227cd2f2c..fc673c4422f 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -41,7 +41,6 @@ pub mod rt {
     pub use parse::new_parser_from_tts;
     pub use codemap::{BytePos, span, dummy_spanned};
 
-    use print::pprust;
     use print::pprust::{item_to_str, ty_to_str};
 
     pub trait ToTokens {
@@ -678,10 +677,11 @@ fn expand_tts(cx: @ext_ctxt,
     // We want to emit a block expression that does a sequence of 'use's to
     // import the runtime module, followed by a tt-building expression.
 
-    let uses = ~[ build::mk_glob_use(cx, sp, ids_ext(cx, ~[~"syntax",
-                                                           ~"ext",
-                                                           ~"quote",
-                                                           ~"rt"])) ];
+    let uses = ~[ build::mk_glob_use(cx, sp, ast::public,
+                                     ids_ext(cx, ~[~"syntax",
+                                                   ~"ext",
+                                                   ~"quote",
+                                                   ~"rt"])) ];
 
     // We also bind a single value, sp, to ext_cx.call_site()
     //
diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs
index 9660afb1bc0..1bb40808142 100644
--- a/src/libsyntax/ext/trace_macros.rs
+++ b/src/libsyntax/ext/trace_macros.rs
@@ -34,9 +34,9 @@ pub fn expand_trace_macros(cx: @ext_ctxt,
         rdr.dup()
     );
 
-    if rust_parser.is_keyword(&~"true") {
+    if rust_parser.is_keyword("true") {
         cx.set_trace_macros(true);
-    } else if rust_parser.is_keyword(&~"false") {
+    } else if rust_parser.is_keyword("false") {
         cx.set_trace_macros(false);
     } else {
         cx.span_fatal(sp, ~"trace_macros! only accepts `true` or `false`")
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index f6dbbbf420d..275a7b963a4 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -589,6 +589,7 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
                 purity: f.purity,
                 region: f.region,
                 onceness: f.onceness,
+                bounds: f.bounds.map(|x| fold_ty_param_bound(x, fld)),
                 decl: fold_fn_decl(&f.decl, fld),
                 lifetimes: copy f.lifetimes,
             })
diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs
index a98e93eec84..fb3622396c9 100644
--- a/src/libsyntax/opt_vec.rs
+++ b/src/libsyntax/opt_vec.rs
@@ -20,8 +20,7 @@ use core::prelude::*;
 use core::old_iter;
 use core::old_iter::BaseIter;
 
-#[auto_encode]
-#[auto_decode]
+#[deriving(Encodable, Decodable)]
 pub enum OptVec<T> {
     Empty,
     Vec(~[T])
diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs
index 322f294836b..6595343654f 100644
--- a/src/libsyntax/parse/common.rs
+++ b/src/libsyntax/parse/common.rs
@@ -137,27 +137,27 @@ pub impl Parser {
 
     // A sanity check that the word we are asking for is a known keyword
     // NOTE: this could be done statically....
-    fn require_keyword(&self, word: &~str) {
-        if !self.keywords.contains(word) {
-            self.bug(fmt!("unknown keyword: %s", *word));
+    fn require_keyword(&self, word: &str) {
+        if !self.keywords.contains_equiv(&word) {
+            self.bug(fmt!("unknown keyword: %s", word));
         }
     }
 
     // return true when this token represents the given string, and is not
     // followed immediately by :: .
-    fn token_is_word(&self, word: &~str, tok: &token::Token) -> bool {
+    fn token_is_word(&self, word: &str, tok: &token::Token) -> bool {
         match *tok {
-            token::IDENT(sid, false) => { *self.id_to_str(sid) == *word }
+            token::IDENT(sid, false) => { word == *self.id_to_str(sid) }
              _ => { false }
         }
     }
 
-    fn token_is_keyword(&self, word: &~str, tok: &token::Token) -> bool {
+    fn token_is_keyword(&self, word: &str, tok: &token::Token) -> bool {
         self.require_keyword(word);
         self.token_is_word(word, tok)
     }
 
-    fn is_keyword(&self, word: &~str) -> bool {
+    fn is_keyword(&self, word: &str) -> bool {
         self.token_is_keyword(word, &copy *self.token)
     }
 
@@ -177,10 +177,10 @@ pub impl Parser {
     // if the given word is not a keyword, signal an error.
     // if the next token is the given keyword, eat it and return
     // true. Otherwise, return false.
-    fn eat_keyword(&self, word: &~str) -> bool {
+    fn eat_keyword(&self, word: &str) -> bool {
         self.require_keyword(word);
         let is_kw = match *self.token {
-            token::IDENT(sid, false) => *word == *self.id_to_str(sid),
+            token::IDENT(sid, false) => word == *self.id_to_str(sid),
             _ => false
         };
         if is_kw { self.bump() }
@@ -190,13 +190,13 @@ pub impl Parser {
     // if the given word is not a keyword, signal an error.
     // if the next token is not the given word, signal an error.
     // otherwise, eat it.
-    fn expect_keyword(&self, word: &~str) {
+    fn expect_keyword(&self, word: &str) {
         self.require_keyword(word);
         if !self.eat_keyword(word) {
             self.fatal(
                 fmt!(
                     "expected `%s`, found `%s`",
-                    *word,
+                    word,
                     self.this_token_to_str()
                 )
             );
@@ -204,8 +204,8 @@ pub impl Parser {
     }
 
     // return true if the given string is a strict keyword
-    fn is_strict_keyword(&self, word: &~str) -> bool {
-        self.strict_keywords.contains(word)
+    fn is_strict_keyword(&self, word: &str) -> bool {
+        self.strict_keywords.contains_equiv(&word)
     }
 
     // signal an error if the current token is a strict keyword
@@ -213,23 +213,23 @@ pub impl Parser {
         match *self.token {
             token::IDENT(_, false) => {
                 let w = token_to_str(self.reader, &copy *self.token);
-                self.check_strict_keywords_(&w);
+                self.check_strict_keywords_(w);
             }
             _ => ()
         }
     }
 
     // signal an error if the given string is a strict keyword
-    fn check_strict_keywords_(&self, w: &~str) {
+    fn check_strict_keywords_(&self, w: &str) {
         if self.is_strict_keyword(w) {
             self.span_err(*self.last_span,
-                          fmt!("found `%s` in ident position", *w));
+                          fmt!("found `%s` in ident position", w));
         }
     }
 
     // return true if this is a reserved keyword
-    fn is_reserved_keyword(&self, word: &~str) -> bool {
-        self.reserved_keywords.contains(word)
+    fn is_reserved_keyword(&self, word: &str) -> bool {
+        self.reserved_keywords.contains_equiv(&word)
     }
 
     // signal an error if the current token is a reserved keyword
@@ -237,16 +237,16 @@ pub impl Parser {
         match *self.token {
             token::IDENT(_, false) => {
                 let w = token_to_str(self.reader, &copy *self.token);
-                self.check_reserved_keywords_(&w);
+                self.check_reserved_keywords_(w);
             }
             _ => ()
         }
     }
 
     // signal an error if the given string is a reserved keyword
-    fn check_reserved_keywords_(&self, w: &~str) {
+    fn check_reserved_keywords_(&self, w: &str) {
         if self.is_reserved_keyword(w) {
-            self.fatal(fmt!("`%s` is a reserved keyword", *w));
+            self.fatal(fmt!("`%s` is a reserved keyword", w));
         }
     }
 
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index 211d123e887..859fde90e29 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -302,9 +302,9 @@ pub impl Parser {
     }
 
     fn try_parse_obsolete_priv_section(&self, attrs: &[attribute]) -> bool {
-        if self.is_keyword(&~"priv") && self.look_ahead(1) == token::LBRACE {
+        if self.is_keyword("priv") && self.look_ahead(1) == token::LBRACE {
             self.obsolete(copy *self.span, ObsoletePrivSection);
-            self.eat_keyword(&~"priv");
+            self.eat_keyword("priv");
             self.bump();
             while *self.token != token::RBRACE {
                 self.parse_single_struct_field(ast::private, attrs.to_owned());
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index b76098858cb..25b45a5f3b5 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -338,10 +338,10 @@ pub impl Parser {
 
     // is this one of the keywords that signals a closure type?
     fn token_is_closure_keyword(&self, tok: &token::Token) -> bool {
-        self.token_is_keyword(&~"pure", tok) ||
-            self.token_is_keyword(&~"unsafe", tok) ||
-            self.token_is_keyword(&~"once", tok) ||
-            self.token_is_keyword(&~"fn", tok)
+        self.token_is_keyword("pure", tok) ||
+            self.token_is_keyword("unsafe", tok) ||
+            self.token_is_keyword("once", tok) ||
+            self.token_is_keyword("fn", tok)
     }
 
     fn token_is_lifetime(&self, tok: &token::Token) -> bool {
@@ -378,7 +378,7 @@ pub impl Parser {
         let opt_abis = self.parse_opt_abis();
         let abis = opt_abis.get_or_default(AbiSet::Rust());
         let purity = self.parse_unsafety();
-        self.expect_keyword(&~"fn");
+        self.expect_keyword("fn");
         let (decl, lifetimes) = self.parse_ty_fn_decl();
         return ty_bare_fn(@TyBareFn {
             abis: abis,
@@ -395,12 +395,13 @@ pub impl Parser {
                         -> ty_ {
         /*
 
-        (&|~|@) ['r] [pure|unsafe] [once] fn <'lt> (S) -> T
-        ^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^    ^~~~^ ^~^    ^
-           |     |     |             |         |    |     |
-           |     |     |             |         |    |   Return type
-           |     |     |             |         |  Argument types
-           |     |     |             |     Lifetimes
+        (&|~|@) ['r] [pure|unsafe] [once] fn [:Bounds] <'lt> (S) -> T
+        ^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^    ^~~~~~~~^ ^~~~^ ^~^    ^
+           |     |     |             |           |       |    |     |
+           |     |     |             |           |       |    |   Return type
+           |     |     |             |           |       |  Argument types
+           |     |     |             |           |   Lifetimes
+           |     |     |             |       Closure bounds
            |     |     |          Once-ness (a.k.a., affine)
            |     |   Purity
            | Lifetime bound
@@ -413,7 +414,8 @@ pub impl Parser {
 
         let purity = self.parse_unsafety();
         let onceness = parse_onceness(self);
-        self.expect_keyword(&~"fn");
+        self.expect_keyword("fn");
+        let bounds = self.parse_optional_ty_param_bounds();
 
         if self.parse_fn_ty_sigil().is_some() {
             self.obsolete(*self.span, ObsoletePostFnTySigil);
@@ -426,12 +428,13 @@ pub impl Parser {
             region: region,
             purity: purity,
             onceness: onceness,
+            bounds: bounds,
             decl: decl,
             lifetimes: lifetimes,
         });
 
         fn parse_onceness(this: &Parser) -> Onceness {
-            if this.eat_keyword(&~"once") {
+            if this.eat_keyword(~"once") {
                 Once
             } else {
                 Many
@@ -441,10 +444,10 @@ pub impl Parser {
 
     // looks like this should be called parse_unsafety
     fn parse_unsafety(&self) -> purity {
-        if self.eat_keyword(&~"pure") {
+        if self.eat_keyword("pure") {
             self.obsolete(*self.last_span, ObsoletePurity);
             return impure_fn;
-        } else if self.eat_keyword(&~"unsafe") {
+        } else if self.eat_keyword("unsafe") {
             return unsafe_fn;
         } else {
             return impure_fn;
@@ -699,7 +702,7 @@ pub impl Parser {
             // BORROWED POINTER
             self.bump();
             self.parse_borrowed_pointee()
-        } else if self.eat_keyword(&~"extern") {
+        } else if self.eat_keyword("extern") {
             // EXTERN FUNCTION
             self.parse_ty_bare_fn()
         } else if self.token_is_closure_keyword(&copy *self.token) {
@@ -823,7 +826,7 @@ pub impl Parser {
         let mut is_mutbl = false;
         let pat = if require_name || self.is_named_argument() {
             self.parse_arg_mode();
-            is_mutbl = self.eat_keyword(&~"mut");
+            is_mutbl = self.eat_keyword("mut");
             let pat = self.parse_pat(false);
             self.expect(&token::COLON);
             pat
@@ -851,7 +854,7 @@ pub impl Parser {
     // parse an argument in a lambda header e.g. |arg, arg|
     fn parse_fn_block_arg(&self) -> arg_or_capture_item {
         self.parse_arg_mode();
-        let is_mutbl = self.eat_keyword(&~"mut");
+        let is_mutbl = self.eat_keyword("mut");
         let pat = self.parse_pat(false);
         let t = if self.eat(&token::COLON) {
             self.parse_ty(false)
@@ -902,9 +905,9 @@ pub impl Parser {
     // matches lit = true | false | token_lit
     fn parse_lit(&self) -> lit {
         let lo = self.span.lo;
-        let lit = if self.eat_keyword(&~"true") {
+        let lit = if self.eat_keyword("true") {
             lit_bool(true)
-        } else if self.eat_keyword(&~"false") {
+        } else if self.eat_keyword("false") {
             lit_bool(false)
         } else {
             // XXX: This is a really bad copy!
@@ -1140,15 +1143,15 @@ pub impl Parser {
     }
 
     fn token_is_mutability(&self, tok: &token::Token) -> bool {
-        self.token_is_keyword(&~"mut", tok) ||
-        self.token_is_keyword(&~"const", tok)
+        self.token_is_keyword("mut", tok) ||
+        self.token_is_keyword("const", tok)
     }
 
     // parse mutability declaration (mut/const/imm)
     fn parse_mutability(&self) -> mutability {
-        if self.eat_keyword(&~"mut") {
+        if self.eat_keyword("mut") {
             m_mutbl
-        } else if self.eat_keyword(&~"const") {
+        } else if self.eat_keyword("const") {
             m_const
         } else {
             m_imm
@@ -1246,30 +1249,30 @@ pub impl Parser {
                                  expr_block(blk));
         } else if token::is_bar(&*self.token) {
             return self.parse_lambda_expr();
-        } else if self.eat_keyword(&~"self") {
+        } else if self.eat_keyword("self") {
             ex = expr_self;
             hi = self.span.hi;
-        } else if self.eat_keyword(&~"if") {
+        } else if self.eat_keyword("if") {
             return self.parse_if_expr();
-        } else if self.eat_keyword(&~"for") {
+        } else if self.eat_keyword("for") {
             return self.parse_sugary_call_expr(~"for", ForSugar,
                                                expr_loop_body);
-        } else if self.eat_keyword(&~"do") {
+        } else if self.eat_keyword("do") {
             return self.parse_sugary_call_expr(~"do", DoSugar,
                                                expr_do_body);
-        } else if self.eat_keyword(&~"while") {
+        } else if self.eat_keyword("while") {
             return self.parse_while_expr();
         } else if self.token_is_lifetime(&*self.token) {
             let lifetime = self.get_lifetime(&*self.token);
             self.bump();
             self.expect(&token::COLON);
-            self.expect_keyword(&~"loop");
+            self.expect_keyword("loop");
             return self.parse_loop_expr(Some(lifetime));
-        } else if self.eat_keyword(&~"loop") {
+        } else if self.eat_keyword("loop") {
             return self.parse_loop_expr(None);
-        } else if self.eat_keyword(&~"match") {
+        } else if self.eat_keyword("match") {
             return self.parse_match_expr();
-        } else if self.eat_keyword(&~"unsafe") {
+        } else if self.eat_keyword("unsafe") {
             return self.parse_block_expr(lo, unsafe_blk);
         } else if *self.token == token::LBRACKET {
             self.bump();
@@ -1309,7 +1312,7 @@ pub impl Parser {
                 }
             }
             hi = self.span.hi;
-        } else if self.eat_keyword(&~"__log") {
+        } else if self.eat_keyword("__log") {
             // LOG expression
             self.expect(&token::LPAREN);
             let lvl = self.parse_expr();
@@ -1318,14 +1321,14 @@ pub impl Parser {
             ex = expr_log(lvl, e);
             hi = self.span.hi;
             self.expect(&token::RPAREN);
-        } else if self.eat_keyword(&~"return") {
+        } else if self.eat_keyword("return") {
             // RETURN expression
             if can_begin_expr(&*self.token) {
                 let e = self.parse_expr();
                 hi = e.span.hi;
                 ex = expr_ret(Some(e));
             } else { ex = expr_ret(None); }
-        } else if self.eat_keyword(&~"break") {
+        } else if self.eat_keyword("break") {
             // BREAK expression
             if self.token_is_lifetime(&*self.token) {
                 let lifetime = self.get_lifetime(&*self.token);
@@ -1335,14 +1338,14 @@ pub impl Parser {
                 ex = expr_break(None);
             }
             hi = self.span.hi;
-        } else if self.eat_keyword(&~"copy") {
+        } else if self.eat_keyword("copy") {
             // COPY expression
             let e = self.parse_expr();
             ex = expr_copy(e);
             hi = e.span.hi;
         } else if *self.token == token::MOD_SEP ||
-                is_ident(&*self.token) && !self.is_keyword(&~"true") &&
-                !self.is_keyword(&~"false") {
+                is_ident(&*self.token) && !self.is_keyword("true") &&
+                !self.is_keyword("false") {
             let pth = self.parse_path_with_tps(true);
 
             // `!`, as an operator, is prefix, so we know this isn't that
@@ -1822,7 +1825,7 @@ pub impl Parser {
                     }
                 }
                 None => {
-                    if as_prec > min_prec && self.eat_keyword(&~"as") {
+                    if as_prec > min_prec && self.eat_keyword("as") {
                         let rhs = self.parse_ty(true);
                         let _as = self.mk_expr(lhs.span.lo,
                                                rhs.span.hi,
@@ -1896,7 +1899,7 @@ pub impl Parser {
         let thn = self.parse_block();
         let mut els: Option<@expr> = None;
         let mut hi = thn.span.hi;
-        if self.eat_keyword(&~"else") {
+        if self.eat_keyword("else") {
             let elexpr = self.parse_else_expr();
             els = Some(elexpr);
             hi = elexpr.span.hi;
@@ -1963,7 +1966,7 @@ pub impl Parser {
     }
 
     fn parse_else_expr(&self) -> @expr {
-        if self.eat_keyword(&~"if") {
+        if self.eat_keyword("if") {
             return self.parse_if_expr();
         } else {
             let blk = self.parse_block();
@@ -2077,7 +2080,7 @@ pub impl Parser {
     fn looking_at_record_literal(&self) -> bool {
         let lookahead = self.look_ahead(1);
         *self.token == token::LBRACE &&
-            (self.token_is_keyword(&~"mut", &lookahead) ||
+            (self.token_is_keyword("mut", &lookahead) ||
              (is_plain_ident(&lookahead) &&
               self.look_ahead(2) == token::COLON))
     }
@@ -2090,7 +2093,7 @@ pub impl Parser {
         while *self.token != token::RBRACE {
             let pats = self.parse_pats();
             let mut guard = None;
-            if self.eat_keyword(&~"if") { guard = Some(self.parse_expr()); }
+            if self.eat_keyword("if") { guard = Some(self.parse_expr()); }
             self.expect(&token::FAT_ARROW);
             let expr = self.parse_expr_res(RESTRICT_STMT_EXPR);
 
@@ -2379,8 +2382,8 @@ pub impl Parser {
           }
           ref tok => {
             if !is_ident_or_path(tok)
-                || self.is_keyword(&~"true")
-                || self.is_keyword(&~"false")
+                || self.is_keyword("true")
+                || self.is_keyword("false")
             {
                 // Parse an expression pattern or exp .. exp.
                 //
@@ -2399,11 +2402,11 @@ pub impl Parser {
                 } else {
                     pat = pat_lit(val);
                 }
-            } else if self.eat_keyword(&~"ref") {
+            } else if self.eat_keyword("ref") {
                 // parse ref pat
                 let mutbl = self.parse_mutability();
                 pat = self.parse_pat_ident(refutable, bind_by_ref(mutbl));
-            } else if self.eat_keyword(&~"copy") {
+            } else if self.eat_keyword("copy") {
                 // parse copy pat
                 pat = self.parse_pat_ident(refutable, bind_by_copy);
             } else {
@@ -2552,7 +2555,7 @@ pub impl Parser {
 
     // parse a "let" stmt
     fn parse_let(&self) -> @decl {
-        let is_mutbl = self.eat_keyword(&~"mut");
+        let is_mutbl = self.eat_keyword("mut");
         let lo = self.span.lo;
         let mut locals = ~[self.parse_local(is_mutbl)];
         while self.eat(&token::COMMA) {
@@ -2566,7 +2569,7 @@ pub impl Parser {
                          pr: visibility,
                          attrs: ~[attribute]) -> @struct_field {
         let lo = self.span.lo;
-        if self.eat_keyword(&~"mut") {
+        if self.eat_keyword("mut") {
             // Do nothing, for backwards compatibility.
             // XXX: Remove after snapshot.
         }
@@ -2596,9 +2599,9 @@ pub impl Parser {
         }
 
         let lo = self.span.lo;
-        if self.is_keyword(&~"let") {
+        if self.is_keyword("let") {
             check_expected_item(self, first_item_attrs);
-            self.expect_keyword(&~"let");
+            self.expect_keyword("let");
             let decl = self.parse_let();
             return @spanned(lo, decl.span.hi, stmt_decl(decl, self.get_id()));
         } else if is_ident(&*self.token)
@@ -2685,7 +2688,7 @@ pub impl Parser {
         maybe_whole!(self, nt_block);
 
         let lo = self.span.lo;
-        if self.eat_keyword(&~"unsafe") {
+        if self.eat_keyword("unsafe") {
             self.obsolete(copy *self.span, ObsoleteUnsafeBlock);
         }
         self.expect(&token::LBRACE);
@@ -2700,7 +2703,7 @@ pub impl Parser {
         maybe_whole!(pair_empty self, nt_block);
 
         let lo = self.span.lo;
-        if self.eat_keyword(&~"unsafe") {
+        if self.eat_keyword("unsafe") {
             self.obsolete(copy *self.span, ObsoleteUnsafeBlock);
         }
         self.expect(&token::LBRACE);
@@ -2834,10 +2837,10 @@ pub impl Parser {
     }
 
     fn parse_optional_purity(&self) -> ast::purity {
-        if self.eat_keyword(&~"pure") {
+        if self.eat_keyword("pure") {
             self.obsolete(*self.last_span, ObsoletePurity);
             ast::impure_fn
-        } else if self.eat_keyword(&~"unsafe") {
+        } else if self.eat_keyword("unsafe") {
             ast::unsafe_fn
         } else {
             ast::impure_fn
@@ -2845,15 +2848,15 @@ pub impl Parser {
     }
 
     fn parse_optional_onceness(&self) -> ast::Onceness {
-        if self.eat_keyword(&~"once") { ast::Once } else { ast::Many }
+        if self.eat_keyword("once") { ast::Once } else { ast::Many }
     }
 
     // matches optbounds = ( ( : ( boundseq )? )? )
     // where   boundseq  = ( bound + boundseq ) | bound
     // and     bound     = 'static | ty
-    fn parse_optional_ty_param_bounds(&self) -> @OptVec<TyParamBound> {
+    fn parse_optional_ty_param_bounds(&self) -> OptVec<TyParamBound> {
         if !self.eat(&token::COLON) {
-            return @opt_vec::Empty;
+            return opt_vec::Empty;
         }
 
         let mut result = opt_vec::Empty;
@@ -2907,13 +2910,13 @@ pub impl Parser {
             }
         }
 
-        return @result;
+        return result;
     }
 
     // matches typaram = IDENT optbounds
     fn parse_ty_param(&self) -> TyParam {
         let ident = self.parse_ident();
-        let bounds = self.parse_optional_ty_param_bounds();
+        let bounds = @self.parse_optional_ty_param_bounds();
         ast::TyParam { ident: ident, id: self.get_id(), bounds: bounds }
     }
 
@@ -3008,10 +3011,10 @@ pub impl Parser {
             p: &Parser
         ) -> ast::explicit_self_ {
             // We need to make sure it isn't a mode or a type
-            if p.token_is_keyword(&~"self", &p.look_ahead(1)) ||
-                ((p.token_is_keyword(&~"const", &p.look_ahead(1)) ||
-                  p.token_is_keyword(&~"mut", &p.look_ahead(1))) &&
-                 p.token_is_keyword(&~"self", &p.look_ahead(2))) {
+            if p.token_is_keyword("self", &p.look_ahead(1)) ||
+                ((p.token_is_keyword("const", &p.look_ahead(1)) ||
+                  p.token_is_keyword("mut", &p.look_ahead(1))) &&
+                 p.token_is_keyword("self", &p.look_ahead(2))) {
 
                 p.bump();
                 let mutability = p.parse_mutability();
@@ -3032,25 +3035,25 @@ pub impl Parser {
             //
             // We already know that the current token is `&`.
 
-            if (this.token_is_keyword(&~"self", &this.look_ahead(1))) {
+            if (this.token_is_keyword("self", &this.look_ahead(1))) {
                 this.bump();
                 this.expect_self_ident();
                 sty_region(None, m_imm)
             } else if (this.token_is_mutability(&this.look_ahead(1)) &&
-                       this.token_is_keyword(&~"self", &this.look_ahead(2))) {
+                       this.token_is_keyword("self", &this.look_ahead(2))) {
                 this.bump();
                 let mutability = this.parse_mutability();
                 this.expect_self_ident();
                 sty_region(None, mutability)
             } else if (this.token_is_lifetime(&this.look_ahead(1)) &&
-                       this.token_is_keyword(&~"self", &this.look_ahead(2))) {
+                       this.token_is_keyword("self", &this.look_ahead(2))) {
                 this.bump();
                 let lifetime = @this.parse_lifetime();
                 this.expect_self_ident();
                 sty_region(Some(lifetime), m_imm)
             } else if (this.token_is_lifetime(&this.look_ahead(1)) &&
                        this.token_is_mutability(&this.look_ahead(2)) &&
-                       this.token_is_keyword(&~"self", &this.look_ahead(3))) {
+                       this.token_is_keyword("self", &this.look_ahead(3))) {
                 this.bump();
                 let lifetime = @this.parse_lifetime();
                 let mutability = this.parse_mutability();
@@ -3259,7 +3262,7 @@ pub impl Parser {
         let mut ty = self.parse_ty(false);
 
         // Parse traits, if necessary.
-        let opt_trait = if could_be_trait && self.eat_keyword(&~"for") {
+        let opt_trait = if could_be_trait && self.eat_keyword("for") {
             // New-style trait. Reinterpret the type as a trait.
             let opt_trait_ref = match ty.node {
                 ty_path(path, node_id) => {
@@ -3434,11 +3437,11 @@ pub impl Parser {
             return ~[];
         }
 
-        if self.eat_keyword(&~"priv") {
+        if self.eat_keyword("priv") {
             return ~[self.parse_single_struct_field(private, attrs)]
         }
 
-        if self.eat_keyword(&~"pub") {
+        if self.eat_keyword("pub") {
            return ~[self.parse_single_struct_field(public, attrs)];
         }
 
@@ -3451,13 +3454,13 @@ pub impl Parser {
 
     // parse visiility: PUB, PRIV, or nothing
     fn parse_visibility(&self) -> visibility {
-        if self.eat_keyword(&~"pub") { public }
-        else if self.eat_keyword(&~"priv") { private }
+        if self.eat_keyword("pub") { public }
+        else if self.eat_keyword("priv") { private }
         else { inherited }
     }
 
     fn parse_staticness(&self) -> bool {
-        if self.eat_keyword(&~"static") {
+        if self.eat_keyword("static") {
             self.obsolete(*self.last_span, ObsoleteStaticMethod);
             true
         } else {
@@ -3677,10 +3680,10 @@ pub impl Parser {
         let lo = self.span.lo;
 
         // XXX: Obsolete; remove after snap.
-        if self.eat_keyword(&~"const") {
+        if self.eat_keyword("const") {
             self.obsolete(*self.last_span, ObsoleteConstItem);
         } else {
-            self.expect_keyword(&~"static");
+            self.expect_keyword("static");
         }
 
         let ident = self.parse_ident();
@@ -3698,14 +3701,14 @@ pub impl Parser {
 
     // parse safe/unsafe and fn
     fn parse_fn_purity(&self) -> purity {
-        if self.eat_keyword(&~"fn") { impure_fn }
-        else if self.eat_keyword(&~"pure") {
+        if self.eat_keyword("fn") { impure_fn }
+        else if self.eat_keyword("pure") {
             self.obsolete(*self.last_span, ObsoletePurity);
-            self.expect_keyword(&~"fn");
+            self.expect_keyword("fn");
             // NB: We parse this as impure for bootstrapping purposes.
             impure_fn
-        } else if self.eat_keyword(&~"unsafe") {
-            self.expect_keyword(&~"fn");
+        } else if self.eat_keyword("unsafe") {
+            self.expect_keyword("fn");
             unsafe_fn
         }
         else { self.unexpected(); }
@@ -3743,9 +3746,9 @@ pub impl Parser {
                               items_allowed: bool)
                               -> item_or_view_item {
         let mut must_be_named_mod = false;
-        if self.is_keyword(&~"mod") {
+        if self.is_keyword("mod") {
             must_be_named_mod = true;
-            self.expect_keyword(&~"mod");
+            self.expect_keyword("mod");
         } else if *self.token != token::LBRACE {
             self.span_fatal(
                 copy *self.span,
@@ -4030,7 +4033,7 @@ pub impl Parser {
         let visibility = self.parse_visibility();
 
         // must be a view item:
-        if self.eat_keyword(&~"use") {
+        if self.eat_keyword("use") {
             // USE ITEM (iovi_view_item)
             let view_item = self.parse_use();
             self.expect(&token::SEMI);
@@ -4042,10 +4045,10 @@ pub impl Parser {
             });
         }
         // either a view item or an item:
-        if self.eat_keyword(&~"extern") {
+        if self.eat_keyword("extern") {
             let opt_abis = self.parse_opt_abis();
 
-            if self.eat_keyword(&~"fn") {
+            if self.eat_keyword("fn") {
                 // EXTERN FUNCTION ITEM
                 let abis = opt_abis.get_or_default(AbiSet::C());
                 let (ident, item_, extra_attrs) =
@@ -4061,11 +4064,11 @@ pub impl Parser {
             }
         }
         // the rest are all guaranteed to be items:
-        if (self.is_keyword(&~"const") ||
-            (self.is_keyword(&~"static") &&
-             !self.token_is_keyword(&~"fn", &self.look_ahead(1)))) {
+        if (self.is_keyword("const") ||
+            (self.is_keyword("static") &&
+             !self.token_is_keyword("fn", &self.look_ahead(1)))) {
             // CONST / STATIC ITEM
-            if self.is_keyword(&~"const") {
+            if self.is_keyword("const") {
                 self.obsolete(*self.span, ObsoleteConstItem);
             }
             self.bump();
@@ -4074,7 +4077,7 @@ pub impl Parser {
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if self.is_keyword(&~"fn") &&
+        if self.is_keyword("fn") &&
             !self.fn_expr_lookahead(self.look_ahead(1u)) {
             // FUNCTION ITEM
             self.bump();
@@ -4084,28 +4087,28 @@ pub impl Parser {
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if self.eat_keyword(&~"pure") {
+        if self.eat_keyword("pure") {
             // PURE FUNCTION ITEM (obsolete)
             self.obsolete(*self.last_span, ObsoletePurity);
-            self.expect_keyword(&~"fn");
+            self.expect_keyword("fn");
             let (ident, item_, extra_attrs) =
                 self.parse_item_fn(impure_fn, AbiSet::Rust());
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if self.is_keyword(&~"unsafe")
+        if self.is_keyword("unsafe")
             && self.look_ahead(1u) != token::LBRACE {
             // UNSAFE FUNCTION ITEM
             self.bump();
-            self.expect_keyword(&~"fn");
+            self.expect_keyword("fn");
             let (ident, item_, extra_attrs) =
                 self.parse_item_fn(unsafe_fn, AbiSet::Rust());
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if self.eat_keyword(&~"mod") {
+        if self.eat_keyword("mod") {
             // MODULE ITEM
             let (ident, item_, extra_attrs) =
                 self.parse_item_mod(/*bad*/ copy attrs);
@@ -4113,28 +4116,28 @@ pub impl Parser {
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if self.eat_keyword(&~"type") {
+        if self.eat_keyword("type") {
             // TYPE ITEM
             let (ident, item_, extra_attrs) = self.parse_item_type();
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if self.eat_keyword(&~"enum") {
+        if self.eat_keyword("enum") {
             // ENUM ITEM
             let (ident, item_, extra_attrs) = self.parse_item_enum();
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if self.eat_keyword(&~"trait") {
+        if self.eat_keyword("trait") {
             // TRAIT ITEM
             let (ident, item_, extra_attrs) = self.parse_item_trait();
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if self.eat_keyword(&~"impl") {
+        if self.eat_keyword("impl") {
             // IMPL ITEM
             let (ident, item_, extra_attrs) =
                 self.parse_item_impl(visibility);
@@ -4142,7 +4145,7 @@ pub impl Parser {
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if self.eat_keyword(&~"struct") {
+        if self.eat_keyword("struct") {
             // STRUCT ITEM
             let (ident, item_, extra_attrs) = self.parse_item_struct();
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
@@ -4163,13 +4166,13 @@ pub impl Parser {
 
         let visibility = self.parse_visibility();
 
-        if (self.is_keyword(&~"const") || self.is_keyword(&~"static")) {
+        if (self.is_keyword("const") || self.is_keyword("static")) {
             // FOREIGN CONST ITEM
             let item = self.parse_item_foreign_const(visibility, attrs);
             return iovi_foreign_item(item);
         }
-        if (self.is_keyword(&~"fn") || self.is_keyword(&~"pure") ||
-             self.is_keyword(&~"unsafe")) {
+        if (self.is_keyword("fn") || self.is_keyword("pure") ||
+             self.is_keyword("unsafe")) {
             // FOREIGN FUNCTION ITEM
                 let item = self.parse_item_foreign_fn(attrs);
                 return iovi_foreign_item(item);
@@ -4360,16 +4363,16 @@ pub impl Parser {
 
     fn is_view_item(&self) -> bool {
         let tok, next_tok;
-        if !self.is_keyword(&~"pub") && !self.is_keyword(&~"priv") {
+        if !self.is_keyword("pub") && !self.is_keyword("priv") {
             tok = copy *self.token;
             next_tok = self.look_ahead(1);
         } else {
             tok = self.look_ahead(1);
             next_tok = self.look_ahead(2);
         };
-        self.token_is_keyword(&~"use", &tok)
-            || (self.token_is_keyword(&~"extern", &tok) &&
-                self.token_is_keyword(&~"mod", &next_tok))
+        self.token_is_keyword("use", &tok)
+            || (self.token_is_keyword("extern", &tok) &&
+                self.token_is_keyword("mod", &next_tok))
     }
 
     // parse a view item.
@@ -4379,10 +4382,10 @@ pub impl Parser {
         vis: visibility
     ) -> @view_item {
         let lo = self.span.lo;
-        let node = if self.eat_keyword(&~"use") {
+        let node = if self.eat_keyword("use") {
             self.parse_use()
-        } else if self.eat_keyword(&~"extern") {
-            self.expect_keyword(&~"mod");
+        } else if self.eat_keyword("extern") {
+            self.expect_keyword("mod");
             let ident = self.parse_ident();
             let metadata = self.parse_optional_meta();
             view_item_extern_mod(ident, metadata, self.get_id())
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index fe479ab81f7..36f241b6427 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -18,9 +18,7 @@ use core::cmp::Equiv;
 use core::hashmap::HashSet;
 use core::to_bytes;
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Encodable, Decodable, Eq)]
 pub enum binop {
     PLUS,
     MINUS,
@@ -34,9 +32,7 @@ pub enum binop {
     SHR,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Encodable, Decodable, Eq)]
 pub enum Token {
     /* Expression-operator symbols. */
     EQ,
@@ -97,9 +93,7 @@ pub enum Token {
     EOF,
 }
 
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
+#[deriving(Encodable, Decodable, Eq)]
 /// For interpolation during macro expansion.
 pub enum nonterminal {
     nt_item(@ast::item),
diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc
index 8deca72779e..565a8a18c6f 100644
--- a/src/libsyntax/syntax.rc
+++ b/src/libsyntax/syntax.rc
@@ -78,6 +78,7 @@ pub mod ext {
 
     pub mod fmt;
     pub mod env;
+    pub mod bytes;
     pub mod concat_idents;
     pub mod log_syntax;
     pub mod auto_encode;
diff --git a/src/libuv b/src/libuv
-Subproject 218ab86721eefd7b7e97fa6d9f95a80a1fa8686
+Subproject dfae9c3e958dc086d9c0ab068cd76d196c95a43
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 8c081858d60..9e44abe081c 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -553,7 +553,7 @@ extern "C" LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B,
     li->setVolatile(true);
     li->setAtomic(order);
     li->setAlignment(sizeof(intptr_t));
-    return wrap(unwrap(B)->Insert(li));
+    return wrap(unwrap(B)->Insert(li, Name));
 }
 
 extern "C" LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef B,
diff --git a/src/test/compile-fail/borrowck-rvalues-mutable-bad.rs b/src/test/compile-fail/borrowck-rvalues-mutable-bad.rs
new file mode 100644
index 00000000000..10bef907a28
--- /dev/null
+++ b/src/test/compile-fail/borrowck-rvalues-mutable-bad.rs
@@ -0,0 +1,38 @@
+// 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.
+
+// Tests that rvalue lifetimes is limited to the enclosing trans
+// cleanup scope. It is unclear that this is the correct lifetime for
+// rvalues, but that's what it is right now.
+
+struct Counter {
+    value: uint
+}
+
+impl Counter {
+    fn new(v: uint) -> Counter {
+        Counter {value: v}
+    }
+
+    fn inc<'a>(&'a mut self) -> &'a mut Counter {
+        self.value += 1;
+        self
+    }
+
+    fn get(&self) -> uint {
+        self.value
+    }
+}
+
+pub fn main() {
+    let v = Counter::new(22).inc().inc().get();
+    //~^ ERROR borrowed value does not live long enough
+    assert_eq!(v, 24);;
+}
diff --git a/src/test/compile-fail/closure-bounds-not-builtin.rs b/src/test/compile-fail/closure-bounds-not-builtin.rs
new file mode 100644
index 00000000000..a3484cb33dc
--- /dev/null
+++ b/src/test/compile-fail/closure-bounds-not-builtin.rs
@@ -0,0 +1,8 @@
+
+trait Foo {}
+
+fn take(f: &fn:Foo()) {
+    //~^ ERROR only the builtin traits can be used as closure or object bounds
+}
+
+fn main() {}
\ No newline at end of file
diff --git a/src/test/compile-fail/closure-bounds-subtype.rs b/src/test/compile-fail/closure-bounds-subtype.rs
new file mode 100644
index 00000000000..ebec113cedc
--- /dev/null
+++ b/src/test/compile-fail/closure-bounds-subtype.rs
@@ -0,0 +1,34 @@
+fn take_any(_: &fn()) {
+}
+
+fn take_copyable(_: &fn:Copy()) {
+}
+
+fn take_copyable_owned(_: &fn:Copy+Owned()) {
+}
+
+fn give_any(f: &fn()) {
+    take_any(f);
+    take_copyable(f); //~ ERROR expected bounds `Copy` but found no bounds
+    take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found no bounds
+}
+
+fn give_copyable(f: &fn:Copy()) {
+    take_any(f);
+    take_copyable(f);
+    take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found bounds `Copy`
+}
+
+fn give_owned(f: &fn:Owned()) {
+    take_any(f);
+    take_copyable(f); //~ ERROR expected bounds `Copy` but found bounds `Owned`
+    take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found bounds `Owned`
+}
+
+fn give_copyable_owned(f: &fn:Copy+Owned()) {
+    take_any(f);
+    take_copyable(f);
+    take_copyable_owned(f);
+}
+
+fn main() {}
\ No newline at end of file
diff --git a/src/test/compile-fail/deriving-obsolete.rs b/src/test/compile-fail/deprecated-auto-code.rs
index 298dced1e21..1f7cbfe9807 100644
--- a/src/test/compile-fail/deriving-obsolete.rs
+++ b/src/test/compile-fail/deprecated-auto-code.rs
@@ -8,10 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[deriving_clone] //~ ERROR `#[deriving_clone]` is obsolete; use `#[deriving(Clone)]` instead
-#[deriving_eq] //~ ERROR `#[deriving_eq]` is obsolete; use `#[deriving(Eq)]` instead
-#[deriving_iter_bytes]
-//~^ ERROR `#[deriving_iter_bytes]` is obsolete; use `#[deriving(IterBytes)]` instead
-struct Foo;
+#[auto_encode] //~ ERROR: `#[auto_encode]` is deprecated
+#[auto_decode] //~ ERROR: `#[auto_decode]` is deprecated
+struct A;
 
-pub fn main() { }
+fn main() {}
\ No newline at end of file
diff --git a/src/test/compile-fail/lint-impl-fn.rs b/src/test/compile-fail/lint-impl-fn.rs
new file mode 100644
index 00000000000..3cc0495206d
--- /dev/null
+++ b/src/test/compile-fail/lint-impl-fn.rs
@@ -0,0 +1,37 @@
+// Copyright 2013 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.
+
+#[allow(while_true)];
+
+struct A(int);
+
+impl A {
+    fn foo(&self) { while true {} }
+
+    #[deny(while_true)]
+    fn bar(&self) { while true {} } //~ ERROR: infinite loops
+}
+
+#[deny(while_true)]
+mod foo {
+    struct B(int);
+
+    impl B {
+        fn foo(&self) { while true {} } //~ ERROR: infinite loops
+
+        #[allow(while_true)]
+        fn bar(&self) { while true {} }
+    }
+}
+
+#[deny(while_true)]
+fn main() {
+    while true {} //~ ERROR: infinite loops
+}
diff --git a/src/test/compile-fail/unused-imports-warn.rs b/src/test/compile-fail/lint-unused-imports.rs
index f3b0a1f73f9..f3b0a1f73f9 100644
--- a/src/test/compile-fail/unused-imports-warn.rs
+++ b/src/test/compile-fail/lint-unused-imports.rs
diff --git a/src/test/compile-fail/unused-mut-variables.rs b/src/test/compile-fail/lint-unused-mut-variables.rs
index d1223cd8893..d1223cd8893 100644
--- a/src/test/compile-fail/unused-mut-variables.rs
+++ b/src/test/compile-fail/lint-unused-mut-variables.rs
diff --git a/src/test/compile-fail/unused-unsafe.rs b/src/test/compile-fail/lint-unused-unsafe.rs
index 465e5548f67..465e5548f67 100644
--- a/src/test/compile-fail/unused-unsafe.rs
+++ b/src/test/compile-fail/lint-unused-unsafe.rs
diff --git a/src/test/compile-fail/liveness-dead.rs b/src/test/compile-fail/liveness-dead.rs
index 1d6a7426045..2ab3cb4568a 100644
--- a/src/test/compile-fail/liveness-dead.rs
+++ b/src/test/compile-fail/liveness-dead.rs
@@ -8,12 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#[deny(dead_assignment)];
+
 fn f1(x: &mut int) {
     *x = 1; // no error
 }
 
 fn f2() {
-    let mut x = 3; //~ WARNING value assigned to `x` is never read
+    let mut x = 3; //~ ERROR: value assigned to `x` is never read
     x = 4;
     copy x;
 }
@@ -21,10 +23,7 @@ fn f2() {
 fn f3() {
     let mut x = 3;
     copy x;
-    x = 4; //~ WARNING value assigned to `x` is never read
+    x = 4; //~ ERROR: value assigned to `x` is never read
 }
 
-fn main() { // leave this in here just to trigger compile-fail:
-    let x: int;
-    copy x; //~ ERROR use of possibly uninitialized variable: `x`
-}
+fn main() {}
diff --git a/src/test/compile-fail/syntax-extension-bytes-non-ascii-char-literal.rs b/src/test/compile-fail/syntax-extension-bytes-non-ascii-char-literal.rs
new file mode 100644
index 00000000000..8bdc643f288
--- /dev/null
+++ b/src/test/compile-fail/syntax-extension-bytes-non-ascii-char-literal.rs
@@ -0,0 +1,13 @@
+// Copyright 2013 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 vec = bytes!('λ'); //~ ERROR Non-ascii char literal in bytes!
+}
diff --git a/src/test/compile-fail/syntax-extension-bytes-non-literal.rs b/src/test/compile-fail/syntax-extension-bytes-non-literal.rs
new file mode 100644
index 00000000000..fed6bdc9470
--- /dev/null
+++ b/src/test/compile-fail/syntax-extension-bytes-non-literal.rs
@@ -0,0 +1,13 @@
+// Copyright 2013 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 vec = bytes!(foo); //~ ERROR Non-literal in bytes!
+}
diff --git a/src/test/compile-fail/syntax-extension-bytes-too-large-integer-literal.rs b/src/test/compile-fail/syntax-extension-bytes-too-large-integer-literal.rs
new file mode 100644
index 00000000000..8acb280dfde
--- /dev/null
+++ b/src/test/compile-fail/syntax-extension-bytes-too-large-integer-literal.rs
@@ -0,0 +1,13 @@
+// Copyright 2013 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 vec = bytes!(1024); //~ ERROR Too large integer literal in bytes!
+}
diff --git a/src/test/compile-fail/syntax-extension-bytes-too-large-u8-literal.rs b/src/test/compile-fail/syntax-extension-bytes-too-large-u8-literal.rs
new file mode 100644
index 00000000000..b7d69a3054f
--- /dev/null
+++ b/src/test/compile-fail/syntax-extension-bytes-too-large-u8-literal.rs
@@ -0,0 +1,13 @@
+// Copyright 2013 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 vec = bytes!(1024u8); //~ ERROR Too large u8 literal in bytes!
+}
diff --git a/src/test/compile-fail/syntax-extension-bytes-too-small-integer-literal.rs b/src/test/compile-fail/syntax-extension-bytes-too-small-integer-literal.rs
new file mode 100644
index 00000000000..cec2dc0a8e0
--- /dev/null
+++ b/src/test/compile-fail/syntax-extension-bytes-too-small-integer-literal.rs
@@ -0,0 +1,13 @@
+// Copyright 2013 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 vec = bytes!(-1024); //~ ERROR Non-literal in bytes
+}
diff --git a/src/test/compile-fail/syntax-extension-bytes-too-small-u8-literal.rs b/src/test/compile-fail/syntax-extension-bytes-too-small-u8-literal.rs
new file mode 100644
index 00000000000..2df55a6436c
--- /dev/null
+++ b/src/test/compile-fail/syntax-extension-bytes-too-small-u8-literal.rs
@@ -0,0 +1,13 @@
+// Copyright 2013 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 vec = bytes!(-1024u8); //~ ERROR Non-literal in bytes
+}
diff --git a/src/test/compile-fail/syntax-extension-bytes-unsupported-literal.rs b/src/test/compile-fail/syntax-extension-bytes-unsupported-literal.rs
new file mode 100644
index 00000000000..b7d55385d1c
--- /dev/null
+++ b/src/test/compile-fail/syntax-extension-bytes-unsupported-literal.rs
@@ -0,0 +1,13 @@
+// Copyright 2013 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 vec = bytes!(45f); //~ ERROR Unsupported literal in bytes!
+}
diff --git a/src/test/run-pass/borrowck-rvalues-mutable.rs b/src/test/run-pass/borrowck-rvalues-mutable.rs
new file mode 100644
index 00000000000..cf5a9341c9d
--- /dev/null
+++ b/src/test/run-pass/borrowck-rvalues-mutable.rs
@@ -0,0 +1,30 @@
+// 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.
+
+struct Counter {
+    value: uint
+}
+
+impl Counter {
+    fn new(v: uint) -> Counter {
+        Counter {value: v}
+    }
+
+    fn get_and_inc(&mut self) -> uint {
+        let v = self.value;
+        self.value += 1;
+        v
+    }
+}
+
+pub fn main() {
+    let v = Counter::new(22).get_and_inc();
+    assert_eq!(v, 22);
+}
diff --git a/src/test/run-pass/deriving-clone-enum.rs b/src/test/run-pass/deriving-clone-enum.rs
index 969e1fb5dd6..9ce965aa49f 100644
--- a/src/test/run-pass/deriving-clone-enum.rs
+++ b/src/test/run-pass/deriving-clone-enum.rs
@@ -8,11 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[deriving(Clone)]
+#[deriving(Clone, DeepClone)]
 enum E {
     A,
     B(()),
     C
 }
 
-pub fn main() {}
+pub fn main() {
+    let _ = A.clone();
+    let _ = B(()).deep_clone();
+}
diff --git a/src/test/run-pass/deriving-clone-generic-enum.rs b/src/test/run-pass/deriving-clone-generic-enum.rs
index 23841017e93..78abbf504f3 100644
--- a/src/test/run-pass/deriving-clone-generic-enum.rs
+++ b/src/test/run-pass/deriving-clone-generic-enum.rs
@@ -1,8 +1,21 @@
-#[deriving(Clone)]
+// Copyright 2013 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.
+
+#[deriving(Clone, DeepClone)]
 enum E<T,U> {
     A(T),
     B(T,U),
     C
 }
 
-fn main() {}
+fn main() {
+    let _ = A::<int, int>(1i).clone();
+    let _ = B(1i, 1.234).deep_clone();
+}
diff --git a/src/test/run-pass/deriving-clone-generic-struct.rs b/src/test/run-pass/deriving-clone-generic-struct.rs
index 0a7a5a3aa75..fd300cbc8b7 100644
--- a/src/test/run-pass/deriving-clone-generic-struct.rs
+++ b/src/test/run-pass/deriving-clone-generic-struct.rs
@@ -8,11 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[deriving(Clone)]
+#[deriving(Clone, DeepClone)]
 struct S<T> {
     foo: (),
     bar: (),
     baz: T,
 }
 
-pub fn main() {}
+pub fn main() {
+    let _ = S { foo: (), bar: (), baz: 1i }.clone().deep_clone();
+}
diff --git a/src/test/run-pass/deriving-clone-generic-tuple-struct.rs b/src/test/run-pass/deriving-clone-generic-tuple-struct.rs
index d6a69e8e6ac..c082a11eab8 100644
--- a/src/test/run-pass/deriving-clone-generic-tuple-struct.rs
+++ b/src/test/run-pass/deriving-clone-generic-tuple-struct.rs
@@ -1,4 +1,16 @@
-#[deriving(Clone)]
+// Copyright 2013 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.
+
+#[deriving(Clone, DeepClone)]
 struct S<T>(T, ());
 
-fn main() {}
+fn main() {
+    let _ = S(1i, ()).clone().deep_clone();
+}
diff --git a/src/test/run-pass/deriving-clone-struct.rs b/src/test/run-pass/deriving-clone-struct.rs
index 4dcbadbb3ef..d540b047af7 100644
--- a/src/test/run-pass/deriving-clone-struct.rs
+++ b/src/test/run-pass/deriving-clone-struct.rs
@@ -1,4 +1,14 @@
-#[deriving(Clone)]
+// Copyright 2013 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.
+
+#[deriving(Clone, DeepClone)]
 struct S {
     _int: int,
     _i8: i8,
diff --git a/src/test/run-pass/issue-6130.rs b/src/test/run-pass/issue-6130.rs
new file mode 100644
index 00000000000..642308c0ca1
--- /dev/null
+++ b/src/test/run-pass/issue-6130.rs
@@ -0,0 +1,20 @@
+// Copyright 2013 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.
+
+#[deny(type_limits)];
+
+fn main() {
+    let i: uint = 0;
+    assert!(i <= 0xFFFF_FFFF_u);
+
+    let i: int = 0;
+    assert!(i >= -0x8000_0000_i);
+    assert!(i <= 0x7FFF_FFFF_i);
+}
diff --git a/src/test/run-pass/syntax-extension-bytes.rs b/src/test/run-pass/syntax-extension-bytes.rs
new file mode 100644
index 00000000000..bdaae65bc3c
--- /dev/null
+++ b/src/test/run-pass/syntax-extension-bytes.rs
@@ -0,0 +1,24 @@
+// Copyright 2013 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.
+
+static static_vec: &'static [u8] = bytes!("abc", 0xFF, '!');
+
+fn main() {
+    let vec = bytes!("abc");
+    assert_eq!(vec, &[97_u8, 98_u8, 99_u8]);
+
+    let vec = bytes!("null", 0);
+    assert_eq!(vec, &[110_u8, 117_u8, 108_u8, 108_u8, 0_u8]);
+
+    let vec = bytes!(' ', " ", 32, 32u8);
+    assert_eq!(vec, &[32_u8, 32_u8, 32_u8, 32_u8]);
+
+    assert_eq!(static_vec, &[97_u8, 98_u8, 99_u8, 255_u8, 33_u8]);
+}