summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPaul Stansifer <paul.stansifer@gmail.com>2012-07-26 16:16:28 -0700
committerPaul Stansifer <paul.stansifer@gmail.com>2012-07-26 16:16:28 -0700
commit97422f0f0fdcbdd17a769fa9588e76b8bf8a5bdf (patch)
treea91f89c585b54fccf34cd873d2488d2cb3c09909 /src
parent8209b2e9b383b9e38a09b1ec79c7b5691aeb5d22 (diff)
parent44631722ff234241cb7100103320a402fe4fdfa9 (diff)
downloadrust-97422f0f0fdcbdd17a769fa9588e76b8bf8a5bdf.tar.gz
rust-97422f0f0fdcbdd17a769fa9588e76b8bf8a5bdf.zip
Merge branch 'incoming' of github.com:mozilla/rust
Diffstat (limited to 'src')
-rw-r--r--src/libcore/arc.rs65
-rw-r--r--src/libcore/cmp.rs8
-rw-r--r--src/libcore/core.rc1
-rw-r--r--src/libcore/core.rs5
-rw-r--r--src/libcore/dlist.rs99
-rw-r--r--src/libcore/f32.rs18
-rw-r--r--src/libcore/f64.rs18
-rw-r--r--src/libcore/float.rs48
-rw-r--r--src/libcore/int-template.rs22
-rw-r--r--src/libcore/io.rs6
-rw-r--r--src/libcore/num.rs18
-rw-r--r--src/libcore/ops.rs66
-rw-r--r--src/libcore/pipes.rs108
-rw-r--r--src/libcore/uint-template.rs22
-rw-r--r--src/libstd/cmp.rs10
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/ast_util.rs2
-rw-r--r--src/libsyntax/ext/pipes/ast_builder.rs2
-rw-r--r--src/rustc/driver/driver.rs7
-rw-r--r--src/rustc/driver/session.rs4
-rw-r--r--src/rustc/lib/llvm.rs3
-rw-r--r--src/rustc/metadata/csearch.rs9
-rw-r--r--src/rustc/metadata/decoder.rs19
-rw-r--r--src/rustc/metadata/encoder.rs12
-rw-r--r--src/rustc/middle/astencode.rs4
-rw-r--r--src/rustc/middle/borrowck/categorization.rs2
-rw-r--r--src/rustc/middle/lang_items.rs209
-rw-r--r--src/rustc/middle/region.rs2
-rw-r--r--src/rustc/middle/resolve3.rs23
-rw-r--r--src/rustc/middle/ty.rs2
-rw-r--r--src/rustc/middle/typeck/astconv.rs2
-rw-r--r--src/rustc/middle/typeck/check.rs4
-rw-r--r--src/rustc/middle/typeck/check/regionmanip.rs2
-rw-r--r--src/rustc/rustc.rc1
-rw-r--r--src/rustllvm/RustWrapper.cpp5
-rw-r--r--src/rustllvm/rustllvm.def.in1
-rw-r--r--src/test/compile-fail/not-utf8.binbin0 -> 3036 bytes
-rw-r--r--src/test/compile-fail/not-utf8.rs5
-rw-r--r--src/test/run-pass/issue-3029.rs8
-rw-r--r--src/test/run-pass/issue-868.rs15
-rw-r--r--src/test/run-pass/task-comm-0.rs22
-rw-r--r--src/test/run-pass/task-comm-10.rs21
-rw-r--r--src/test/run-pass/task-comm-11.rs13
-rw-r--r--src/test/run-pass/task-comm-13.rs11
-rw-r--r--src/test/run-pass/task-comm-14.rs14
-rw-r--r--src/test/run-pass/task-comm-15.rs12
-rw-r--r--src/test/run-pass/task-comm-16.rs70
-rw-r--r--src/test/run-pass/task-comm-3.rs16
-rw-r--r--src/test/run-pass/task-comm-4.rs39
-rw-r--r--src/test/run-pass/task-comm-5.rs9
-rw-r--r--src/test/run-pass/task-comm-6.rs34
-rw-r--r--src/test/run-pass/task-comm-7.rs20
-rw-r--r--src/test/run-pass/task-comm-9.rs11
-rw-r--r--src/test/run-pass/trivial-message.rs10
-rw-r--r--src/test/run-pass/unreachable-code.rs31
55 files changed, 772 insertions, 420 deletions
diff --git a/src/libcore/arc.rs b/src/libcore/arc.rs
index 28f07264410..9c46df9731b 100644
--- a/src/libcore/arc.rs
+++ b/src/libcore/arc.rs
@@ -3,10 +3,9 @@
  * share immutable data between tasks.
  */
 
-import comm::{port, chan, methods};
 import sys::methods;
 
-export arc, get, clone, shared_arc, get_arc;
+export arc, get, clone;
 
 export exclusive, methods;
 
@@ -122,49 +121,6 @@ impl methods<T: send> for exclusive<T> {
     }
 }
 
-// Convenience code for sharing arcs between tasks
-
-type get_chan<T: const send> = chan<chan<arc<T>>>;
-
-// (terminate, get)
-type shared_arc<T: const send> = (shared_arc_res, get_chan<T>);
-
-class shared_arc_res {
-   let c: comm::chan<()>;
-   new(c: comm::chan<()>) { self.c = c; }
-   drop { self.c.send(()); }
-}
-
-fn shared_arc<T: send const>(-data: T) -> shared_arc<T> {
-    let a = arc::arc(data);
-    let p = port();
-    let c = chan(p);
-    do task::spawn() |move a| {
-        let mut live = true;
-        let terminate = port();
-        let get = port();
-
-        c.send((chan(terminate), chan(get)));
-
-        while live {
-            alt comm::select2(terminate, get) {
-              either::left(()) { live = false; }
-              either::right(cc) {
-                comm::send(cc, arc::clone(&a));
-              }
-            }
-        }
-    };
-    let (terminate, get) = p.recv();
-    (shared_arc_res(terminate), get)
-}
-
-fn get_arc<T: send const>(c: get_chan<T>) -> arc::arc<T> {
-    let p = port();
-    c.send(chan(p));
-    p.recv()
-}
-
 #[cfg(test)]
 mod tests {
     import comm::*;
@@ -197,25 +153,6 @@ mod tests {
     }
 
     #[test]
-    fn auto_share_arc() {
-        let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-        let (_res, arc_c) = shared_arc(v);
-
-        let p = port();
-        let c = chan(p);
-
-        do task::spawn() {
-            let arc_v = get_arc(arc_c);
-            let v = *get(&arc_v);
-            assert v[2] == 3;
-
-            c.send(());
-        };
-
-        assert p.recv() == ();
-    }
-
-    #[test]
     #[ignore] // this can probably infinite loop too.
     fn exclusive_arc() {
         let mut futures = ~[];
diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs
index 1bdf3b9909a..d10b9603af0 100644
--- a/src/libcore/cmp.rs
+++ b/src/libcore/cmp.rs
@@ -1,10 +1,10 @@
 /// Interfaces used for comparison.
 
-iface ord {
-    fn lt(&&other: self) -> bool;
+trait ord {
+    pure fn lt(&&other: self) -> bool;
 }
 
-iface eq {
-    fn eq(&&other: self) -> bool;
+trait eq {
+    pure fn eq(&&other: self) -> bool;
 }
 
diff --git a/src/libcore/core.rc b/src/libcore/core.rc
index d298ff15a9e..11e305e22e8 100644
--- a/src/libcore/core.rc
+++ b/src/libcore/core.rc
@@ -161,6 +161,7 @@ mod tuple;
 
 // Ubiquitous-utility-type modules
 
+mod ops;
 mod cmp;
 mod num;
 mod hash;
diff --git a/src/libcore/core.rs b/src/libcore/core.rs
index 4738574fdb4..fdf53524188 100644
--- a/src/libcore/core.rs
+++ b/src/libcore/core.rs
@@ -30,6 +30,8 @@ import float::num;
 import f32::num;
 import f64::num;
 import num::num;
+import ops::{const, copy, send, owned};
+import ops::{add, sub, mul, div, modulo, neg, bitops, index};
 
 export path, option, some, none, unreachable;
 export extensions;
@@ -42,6 +44,9 @@ export immutable_copyable_vector, iter_trait_extensions, vec_concat;
 export base_iter, copyable_iter, extended_iter;
 export tuple_ops, extended_tuple_ops;
 export ptr;
+// The following exports are the core operators and kinds
+export const, copy, send, owned;
+export add, sub, mul, div, modulo, neg, bitops, index;
 
 // Export the log levels as global constants. Higher levels mean
 // more-verbosity. Error is the bottom level, default logging level is
diff --git a/src/libcore/dlist.rs b/src/libcore/dlist.rs
index 087194f721d..cd36d14816c 100644
--- a/src/libcore/dlist.rs
+++ b/src/libcore/dlist.rs
@@ -18,12 +18,28 @@ enum dlist_node<T> = @{
     mut next: dlist_link<T>
 };
 
-// Needs to be an @-box so nodes can back-reference it.
-enum dlist<T> = @{
-    mut size: uint,
-    mut hd: dlist_link<T>,
-    mut tl: dlist_link<T>
-};
+class dlist_root<T> {
+    let mut size: uint;
+    let mut hd:   dlist_link<T>;
+    let mut tl:   dlist_link<T>;
+    new() {
+        self.size = 0; self.hd = none; self.tl = none;
+    }
+    drop {
+        /* FIXME (#????) This doesn't work during task failure - the box
+         * annihilator might have killed some of our nodes already. This will
+         * be safe to uncomment when the box annihilator is safer. As is,
+         * this makes test_dlist_cyclic_link below crash the runtime.
+        // Empty the list. Not doing this explicitly would leave cyclic links
+        // around, not to be freed until cycle collection at task exit.
+        while self.hd.is_some() {
+            self.unlink(self.hd.get());
+        }
+        */
+    }
+}
+
+type dlist<T> = @dlist_root<T>;
 
 impl private_methods<T> for dlist_node<T> {
     pure fn assert_links() {
@@ -91,7 +107,7 @@ pure fn new_dlist_node<T>(+data: T) -> dlist_node<T> {
 
 /// Creates a new, empty dlist.
 pure fn new_dlist<T>() -> dlist<T> {
-    dlist(@{mut size: 0, mut hd: none, mut tl: none})
+    @unchecked { dlist_root() }
 }
 
 /// Creates a new dlist with a single element
@@ -118,7 +134,7 @@ fn concat<T>(lists: dlist<dlist<T>>) -> dlist<T> {
     result
 }
 
-impl private_methods<T> for dlist<T> {
+impl private_methods<T> for dlist_root<T> {
     pure fn new_link(-data: T) -> dlist_link<T> {
         some(dlist_node(@{data: data, mut linked: true,
                           mut prev: none, mut next: none}))
@@ -288,20 +304,6 @@ impl extensions<T> for dlist<T> {
         tl.map(|nobe| self.unlink(nobe));
         tl
     }
-    /// Remove data from the head of the list. O(1).
-    fn pop() -> option<T> {
-        do option::map_consume(self.pop_n()) |nobe| {
-            let dlist_node(@{ data: x, _ }) <- nobe;
-            x
-        }
-    }
-    /// Remove data from the tail of the list. O(1).
-    fn pop_tail() -> option<T> {
-        do option::map_consume(self.pop_tail_n()) |nobe| {
-            let dlist_node(@{ data: x, _ }) <- nobe;
-            x
-        }
-    }
     /// Get the node at the list's head. O(1).
     pure fn peek_n() -> option<dlist_node<T>> { self.hd }
     /// Get the node at the list's tail. O(1).
@@ -334,7 +336,7 @@ impl extensions<T> for dlist<T> {
      * to the other list's head. O(1).
      */
     fn append(them: dlist<T>) {
-        if box::ptr_eq(*self, *them) {
+        if box::ptr_eq(self, them) {
             fail ~"Cannot append a dlist to itself!"
         }
         if them.len() > 0 {
@@ -351,7 +353,7 @@ impl extensions<T> for dlist<T> {
      * list's tail to this list's head. O(1).
      */
     fn prepend(them: dlist<T>) {
-        if box::ptr_eq(*self, *them) {
+        if box::ptr_eq(self, them) {
             fail ~"Cannot prepend a dlist to itself!"
         }
         if them.len() > 0 {
@@ -366,15 +368,25 @@ impl extensions<T> for dlist<T> {
 
     /// Reverse the list's elements in place. O(n).
     fn reverse() {
-        let temp = new_dlist::<T>();
+        do option::while_some(self.hd) |nobe| {
+            let next_nobe = nobe.next;
+            self.remove(nobe);
+            self.make_mine(nobe);
+            self.add_head(some(nobe));
+            next_nobe
+        }
+    }
+
+    /**
+     * Remove everything from the list. This is important because the cyclic
+     * links won't otherwise be automatically refcounted-collected. O(n).
+     */
+    fn clear() {
+        // Cute as it would be to simply detach the list and proclaim "O(1)!",
+        // the GC would still be a hidden O(n). Better to be honest about it.
         while !self.is_empty() {
-            let nobe = self.pop_n().get();
-            nobe.linked = true; // meh, kind of disorganised.
-            temp.add_head(some(nobe));
+            let _ = self.pop_n();
         }
-        self.hd   = temp.hd;
-        self.tl   = temp.tl;
-        self.size = temp.size;
     }
 
     /// Iterate over nodes.
@@ -431,6 +443,10 @@ impl extensions<T> for dlist<T> {
 }
 
 impl extensions<T: copy> for dlist<T> {
+    /// Remove data from the head of the list. O(1).
+    fn pop()       -> option<T> { self.pop_n().map       (|nobe| nobe.data) }
+    /// Remove data from the tail of the list. O(1).
+    fn pop_tail()  -> option<T> { self.pop_tail_n().map  (|nobe| nobe.data) }
     /// Get data at the list's head. O(1).
     pure fn peek() -> option<T> { self.peek_n().map      (|nobe| nobe.data) }
     /// Get data at the list's tail. O(1).
@@ -596,6 +612,13 @@ mod tests {
         a.assert_consistent(); assert a.is_empty();
     }
     #[test]
+    fn test_dlist_clear() {
+        let a = from_vec(~[5,4,3,2,1]);
+        a.clear();
+        assert a.len() == 0;
+        a.assert_consistent();
+    }
+    #[test]
     fn test_dlist_is_empty() {
         let empty = new_dlist::<int>();
         let full1 = from_vec(~[1,2,3]);
@@ -847,7 +870,7 @@ mod tests {
         l.assert_consistent(); assert l.is_empty();
     }
     #[test] #[should_fail] #[ignore(cfg(windows))]
-    fn test_asymmetric_link() {
+    fn test_dlist_asymmetric_link() {
         let l = new_dlist::<int>();
         let _one = l.push_n(1);
         let two = l.push_n(2);
@@ -855,7 +878,7 @@ mod tests {
         l.assert_consistent();
     }
     #[test] #[should_fail] #[ignore(cfg(windows))]
-    fn test_cyclic_list() {
+    fn test_dlist_cyclic_list() {
         let l = new_dlist::<int>();
         let one = l.push_n(1);
         let _two = l.push_n(2);
@@ -865,32 +888,32 @@ mod tests {
         l.assert_consistent();
     }
     #[test] #[should_fail] #[ignore(cfg(windows))]
-    fn test_headless() {
+    fn test_dlist_headless() {
         new_dlist::<int>().head();
     }
     #[test] #[should_fail] #[ignore(cfg(windows))]
-    fn test_insert_already_present_before() {
+    fn test_dlist_insert_already_present_before() {
         let l = new_dlist::<int>();
         let one = l.push_n(1);
         let two = l.push_n(2);
         l.insert_n_before(two, one);
     }
     #[test] #[should_fail] #[ignore(cfg(windows))]
-    fn test_insert_already_present_after() {
+    fn test_dlist_insert_already_present_after() {
         let l = new_dlist::<int>();
         let one = l.push_n(1);
         let two = l.push_n(2);
         l.insert_n_after(one, two);
     }
     #[test] #[should_fail] #[ignore(cfg(windows))]
-    fn test_insert_before_orphan() {
+    fn test_dlist_insert_before_orphan() {
         let l = new_dlist::<int>();
         let one = new_dlist_node(1);
         let two = new_dlist_node(2);
         l.insert_n_before(one, two);
     }
     #[test] #[should_fail] #[ignore(cfg(windows))]
-    fn test_insert_after_orphan() {
+    fn test_dlist_insert_after_orphan() {
         let l = new_dlist::<int>();
         let one = new_dlist_node(1);
         let two = new_dlist_node(2);
diff --git a/src/libcore/f32.rs b/src/libcore/f32.rs
index c72aa6e3aef..3e7bc0097f7 100644
--- a/src/libcore/f32.rs
+++ b/src/libcore/f32.rs
@@ -168,15 +168,15 @@ pure fn log2(n: f32) -> f32 {
 }
 
 impl num of num::num for f32 {
-    fn add(&&other: f32)    -> f32 { ret self + other; }
-    fn sub(&&other: f32)    -> f32 { ret self - other; }
-    fn mul(&&other: f32)    -> f32 { ret self * other; }
-    fn div(&&other: f32)    -> f32 { ret self / other; }
-    fn modulo(&&other: f32) -> f32 { ret self % other; }
-    fn neg()                -> f32 { ret -self;        }
-
-    fn to_int()         -> int { ret self as int; }
-    fn from_int(n: int) -> f32 { ret n as f32;    }
+    pure fn add(&&other: f32)    -> f32 { ret self + other; }
+    pure fn sub(&&other: f32)    -> f32 { ret self - other; }
+    pure fn mul(&&other: f32)    -> f32 { ret self * other; }
+    pure fn div(&&other: f32)    -> f32 { ret self / other; }
+    pure fn modulo(&&other: f32) -> f32 { ret self % other; }
+    pure fn neg()                -> f32 { ret -self;        }
+
+    pure fn to_int()         -> int { ret self as int; }
+    pure fn from_int(n: int) -> f32 { ret n as f32;    }
 }
 
 //
diff --git a/src/libcore/f64.rs b/src/libcore/f64.rs
index 40488d9f8f4..9e84c432bad 100644
--- a/src/libcore/f64.rs
+++ b/src/libcore/f64.rs
@@ -195,15 +195,15 @@ pure fn log2(n: f64) -> f64 {
 }
 
 impl num of num::num for f64 {
-    fn add(&&other: f64)    -> f64 { ret self + other; }
-    fn sub(&&other: f64)    -> f64 { ret self - other; }
-    fn mul(&&other: f64)    -> f64 { ret self * other; }
-    fn div(&&other: f64)    -> f64 { ret self / other; }
-    fn modulo(&&other: f64) -> f64 { ret self % other; }
-    fn neg()                -> f64 { ret -self;        }
-
-    fn to_int()         -> int { ret self as int; }
-    fn from_int(n: int) -> f64 { ret n as f64;    }
+    pure fn add(&&other: f64)    -> f64 { ret self + other; }
+    pure fn sub(&&other: f64)    -> f64 { ret self - other; }
+    pure fn mul(&&other: f64)    -> f64 { ret self * other; }
+    pure fn div(&&other: f64)    -> f64 { ret self / other; }
+    pure fn modulo(&&other: f64) -> f64 { ret self % other; }
+    pure fn neg()                -> f64 { ret -self;        }
+
+    pure fn to_int()         -> int { ret self as int; }
+    pure fn from_int(n: int) -> f64 { ret n as f64;    }
 }
 
 //
diff --git a/src/libcore/float.rs b/src/libcore/float.rs
index 0139c60873b..8b8cc4664dc 100644
--- a/src/libcore/float.rs
+++ b/src/libcore/float.rs
@@ -403,32 +403,32 @@ fn pow_with_uint(base: uint, pow: uint) -> float {
     ret total;
 }
 
-fn is_positive(x: float) -> bool { f64::is_positive(x as f64) }
-fn is_negative(x: float) -> bool { f64::is_negative(x as f64) }
-fn is_nonpositive(x: float) -> bool { f64::is_nonpositive(x as f64) }
-fn is_nonnegative(x: float) -> bool { f64::is_nonnegative(x as f64) }
-fn is_zero(x: float) -> bool { f64::is_zero(x as f64) }
-fn is_infinite(x: float) -> bool { f64::is_infinite(x as f64) }
-fn is_finite(x: float) -> bool { f64::is_finite(x as f64) }
-fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) }
-
-fn abs(x: float) -> float { f64::abs(x as f64) as float }
-fn sqrt(x: float) -> float { f64::sqrt(x as f64) as float }
-fn atan(x: float) -> float { f64::atan(x as f64) as float }
-fn sin(x: float) -> float { f64::sin(x as f64) as float }
-fn cos(x: float) -> float { f64::cos(x as f64) as float }
-fn tan(x: float) -> float { f64::tan(x as f64) as float }
+pure fn is_positive(x: float) -> bool { f64::is_positive(x as f64) }
+pure fn is_negative(x: float) -> bool { f64::is_negative(x as f64) }
+pure fn is_nonpositive(x: float) -> bool { f64::is_nonpositive(x as f64) }
+pure fn is_nonnegative(x: float) -> bool { f64::is_nonnegative(x as f64) }
+pure fn is_zero(x: float) -> bool { f64::is_zero(x as f64) }
+pure fn is_infinite(x: float) -> bool { f64::is_infinite(x as f64) }
+pure fn is_finite(x: float) -> bool { f64::is_finite(x as f64) }
+pure fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) }
+
+pure fn abs(x: float) -> float { f64::abs(x as f64) as float }
+pure fn sqrt(x: float) -> float { f64::sqrt(x as f64) as float }
+pure fn atan(x: float) -> float { f64::atan(x as f64) as float }
+pure fn sin(x: float) -> float { f64::sin(x as f64) as float }
+pure fn cos(x: float) -> float { f64::cos(x as f64) as float }
+pure fn tan(x: float) -> float { f64::tan(x as f64) as float }
 
 impl num of num::num for float {
-    fn add(&&other: float)    -> float { ret self + other; }
-    fn sub(&&other: float)    -> float { ret self - other; }
-    fn mul(&&other: float)    -> float { ret self * other; }
-    fn div(&&other: float)    -> float { ret self / other; }
-    fn modulo(&&other: float) -> float { ret self % other; }
-    fn neg()                  -> float { ret -self;        }
-
-    fn to_int()         -> int   { ret self as int; }
-    fn from_int(n: int) -> float { ret n as float;  }
+    pure fn add(&&other: float)    -> float { ret self + other; }
+    pure fn sub(&&other: float)    -> float { ret self - other; }
+    pure fn mul(&&other: float)    -> float { ret self * other; }
+    pure fn div(&&other: float)    -> float { ret self / other; }
+    pure fn modulo(&&other: float) -> float { ret self % other; }
+    pure fn neg()                  -> float { ret -self;        }
+
+    pure fn to_int()         -> int   { ret self as int; }
+    pure fn from_int(n: int) -> float { ret n as float;  }
 }
 
 #[test]
diff --git a/src/libcore/int-template.rs b/src/libcore/int-template.rs
index 02ce125e35c..2b950e4a797 100644
--- a/src/libcore/int-template.rs
+++ b/src/libcore/int-template.rs
@@ -112,27 +112,27 @@ fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
 fn str(i: T) -> ~str { ret to_str(i, 10u); }
 
 impl ord of ord for T {
-    fn lt(&&other: T) -> bool {
+    pure fn lt(&&other: T) -> bool {
         ret self < other;
     }
 }
 
 impl eq of eq for T {
-    fn eq(&&other: T) -> bool {
+    pure fn eq(&&other: T) -> bool {
         ret self == other;
     }
 }
 
 impl num of num::num for T {
-    fn add(&&other: T)    -> T { ret self + other; }
-    fn sub(&&other: T)    -> T { ret self - other; }
-    fn mul(&&other: T)    -> T { ret self * other; }
-    fn div(&&other: T)    -> T { ret self / other; }
-    fn modulo(&&other: T) -> T { ret self % other; }
-    fn neg()              -> T { ret -self;        }
-
-    fn to_int()         -> int { ret self as int; }
-    fn from_int(n: int) -> T   { ret n as T;      }
+    pure fn add(&&other: T)    -> T { ret self + other; }
+    pure fn sub(&&other: T)    -> T { ret self - other; }
+    pure fn mul(&&other: T)    -> T { ret self * other; }
+    pure fn div(&&other: T)    -> T { ret self / other; }
+    pure fn modulo(&&other: T) -> T { ret self % other; }
+    pure fn neg()              -> T { ret -self;        }
+
+    pure fn to_int()         -> int { ret self as int; }
+    pure fn from_int(n: int) -> T   { ret n as T;      }
 }
 
 impl times of iter::times for T {
diff --git a/src/libcore/io.rs b/src/libcore/io.rs
index 25d1b5e6680..3704f2b70da 100644
--- a/src/libcore/io.rs
+++ b/src/libcore/io.rs
@@ -687,7 +687,11 @@ fn seek_in_buf(offset: int, pos: uint, len: uint, whence: seek_style) ->
 
 fn read_whole_file_str(file: ~str) -> result<~str, ~str> {
     result::chain(read_whole_file(file), |bytes| {
-        result::ok(str::from_bytes(bytes))
+        if str::is_utf8(bytes) {
+            result::ok(str::from_bytes(bytes))
+       } else {
+           result::err(file + ~" is not UTF-8")
+       }
     })
 }
 
diff --git a/src/libcore/num.rs b/src/libcore/num.rs
index 130b259c1df..03868527655 100644
--- a/src/libcore/num.rs
+++ b/src/libcore/num.rs
@@ -1,17 +1,17 @@
 /// An interface for numbers.
 
-iface num {
+trait num {
     // FIXME: Cross-crate overloading doesn't work yet. (#2615)
     // FIXME: Interface inheritance. (#2616)
-    fn add(&&other: self) -> self;
-    fn sub(&&other: self) -> self;
-    fn mul(&&other: self) -> self;
-    fn div(&&other: self) -> self;
-    fn modulo(&&other: self) -> self;
-    fn neg() -> self;
+    pure fn add(&&other: self) -> self;
+    pure fn sub(&&other: self) -> self;
+    pure fn mul(&&other: self) -> self;
+    pure fn div(&&other: self) -> self;
+    pure fn modulo(&&other: self) -> self;
+    pure fn neg() -> self;
 
-    fn to_int() -> int;
-    fn from_int(n: int) -> self;    // FIXME (#2376) Static functions.
+    pure fn to_int() -> int;
+    pure fn from_int(n: int) -> self;    // FIXME (#2376) Static functions.
     // n.b. #2376 is for classes, not ifaces, but it could be generalized...
 }
 
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
new file mode 100644
index 00000000000..61efe704974
--- /dev/null
+++ b/src/libcore/ops.rs
@@ -0,0 +1,66 @@
+// Core operators and kinds.
+
+#[lang="const"]
+trait const {
+    // Empty.
+}
+
+#[lang="copy"]
+trait copy {
+    // Empty.
+}
+
+#[lang="send"]
+trait send {
+    // Empty.
+}
+
+#[lang="owned"]
+trait owned {
+    // Empty.
+}
+
+#[lang="add"]
+trait add<RHS,Result> {
+    pure fn add(rhs: RHS) -> Result;
+}
+
+#[lang="sub"]
+trait sub<RHS,Result> {
+    pure fn sub(rhs: RHS) -> Result;
+}
+
+#[lang="mul"]
+trait mul<RHS,Result> {
+    pure fn mul(rhs: RHS) -> Result;
+}
+
+#[lang="div"]
+trait div<RHS,Result> {
+    pure fn div(rhs: RHS) -> Result;
+}
+
+#[lang="modulo"]
+trait modulo<RHS,Result> {
+    pure fn modulo(rhs: RHS) -> Result;
+}
+
+#[lang="neg"]
+trait neg<RHS,Result> {
+    pure fn neg(rhs: RHS) -> Result;
+}
+
+#[lang="bitops"]
+trait bitops<RHS,BitCount,Result> {
+    pure fn and(rhs: RHS) -> Result;
+    pure fn or(rhs: RHS) -> Result;
+    pure fn xor(rhs: RHS) -> Result;
+    pure fn shl(n: BitCount) -> Result;
+    pure fn shr(n: BitCount) -> Result;
+}
+
+#[lang="index"]
+trait index<Index,Result> {
+    pure fn index(index: Index) -> Result;
+}
+
diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs
index 27cd8ef7caf..4ffa040250f 100644
--- a/src/libcore/pipes.rs
+++ b/src/libcore/pipes.rs
@@ -30,59 +30,6 @@ macro_rules! move {
 // places. Once there is unary move, it can be removed.
 fn move<T>(-x: T) -> T { x }
 
-/**
-
-Some thoughts about fixed buffers.
-
-The idea is if a protocol is bounded, we will synthesize a record that
-has a field for each state. Each of these states contains a packet for
-the messages that are legal to be sent in that state. Then, instead of
-allocating, the send code just finds a pointer to the right field and
-uses that instead.
-
-Unforunately, this makes things kind of tricky. We need to be able to
-find the buffer, which means we need to pass it around. This could
-either be associated with the (send|recv)_packet classes, or with the
-packet itself. We will also need some form of reference counting so we
-can track who has the responsibility of freeing the buffer.
-
-We want to preserve the ability to do things like optimistic buffer
-re-use, and skipping over to a new buffer when necessary. What I mean
-is, suppose we had the typical stream protocol. It'd make sense to
-amortize allocation costs by allocating a buffer with say 16
-messages. When the sender gets to the end of the buffer, it could
-check if the receiver is done with the packet in slot 0. If so, it can
-just reuse that one, checking if the receiver is done with the next
-one in each case. If it is ever not done, it just allocates a new
-buffer and skips over to that.
-
-Also, since protocols are in libcore, we have to do this in a way that
-maintains backwards compatibility.
-
-buffer header and buffer. Cast as c_void when necessary.
-
-===
-
-Okay, here are some new ideas.
-
-It'd be nice to keep the bounded/unbounded case as uniform as
-possible. It leads to less code duplication, and less things that can
-go sublty wrong. For the bounded case, we could either have a struct
-with a bunch of unique pointers to pre-allocated packets, or we could
-lay them out inline. Inline layout is better, if for no other reason
-than that we don't have to allocate each packet
-individually. Currently we pass unique packets around as unsafe
-pointers, but they are actually unique pointers. We should instead use
-real unsafe pointers. This makes freeing data and running destructors
-trickier though. Thus, we should allocate all packets in parter of a
-higher level buffer structure. Packets can maintain a pointer to their
-buffer, and this is the part that gets freed.
-
-It might be helpful to have some idea of a semi-unique pointer (like
-being partially pregnant, also like an ARC).
-
-*/
-
 enum state {
     empty,
     full,
@@ -805,6 +752,12 @@ class port_set<T: send> : recv<T> {
         vec::push(self.ports, port)
     }
 
+    fn chan() -> chan<T> {
+        let (ch, po) = stream();
+        self.add(po);
+        ch
+    }
+
     fn try_recv() -> option<T> {
         let mut result = none;
         while result == none && self.ports.len() > 0 {
@@ -869,3 +822,52 @@ impl chan<T: send> of channel<T> for shared_chan<T> {
 fn shared_chan<T:send>(+c: chan<T>) -> shared_chan<T> {
     arc::exclusive(c)
 }
+
+trait select2<T: send, U: send> {
+    fn try_select() -> either<option<T>, option<U>>;
+    fn select() -> either<T, U>;
+}
+
+impl<T: send, U: send, Left: selectable recv<T>, Right: selectable recv<U>>
+    of select2<T, U> for (Left, Right) {
+
+    fn select() -> either<T, U> {
+        alt self {
+          (lp, rp) {
+            alt select2i(lp, rp) {
+              left(())  { left (lp.recv()) }
+              right(()) { right(rp.recv()) }
+            }
+          }
+        }
+    }
+
+    fn try_select() -> either<option<T>, option<U>> {
+        alt self {
+          (lp, rp) {
+            alt select2i(lp, rp) {
+              left(())  { left (lp.try_recv()) }
+              right(()) { right(rp.try_recv()) }
+            }
+          }
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    #[test]
+    fn test_select2() {
+        let (c1, p1) = pipes::stream();
+        let (c2, p2) = pipes::stream();
+
+        c1.send("abc");
+
+        alt (p1, p2).select() {
+          right(_) { fail }
+          _ { }
+        }
+
+        c2.send(123);
+    }
+}
diff --git a/src/libcore/uint-template.rs b/src/libcore/uint-template.rs
index 75e17cd6a9b..9561ed4e65f 100644
--- a/src/libcore/uint-template.rs
+++ b/src/libcore/uint-template.rs
@@ -53,27 +53,27 @@ pure fn compl(i: T) -> T {
 }
 
 impl ord of ord for T {
-    fn lt(&&other: T) -> bool {
+    pure fn lt(&&other: T) -> bool {
         ret self < other;
     }
 }
 
 impl eq of eq for T {
-    fn eq(&&other: T) -> bool {
+    pure fn eq(&&other: T) -> bool {
         ret self == other;
     }
 }
 
 impl num of num::num for T {
-    fn add(&&other: T)    -> T { ret self + other; }
-    fn sub(&&other: T)    -> T { ret self - other; }
-    fn mul(&&other: T)    -> T { ret self * other; }
-    fn div(&&other: T)    -> T { ret self / other; }
-    fn modulo(&&other: T) -> T { ret self % other; }
-    fn neg()              -> T { ret -self;        }
-
-    fn to_int()         -> int { ret self as int; }
-    fn from_int(n: int) -> T   { ret n as T;      }
+    pure fn add(&&other: T)    -> T { ret self + other; }
+    pure fn sub(&&other: T)    -> T { ret self - other; }
+    pure fn mul(&&other: T)    -> T { ret self * other; }
+    pure fn div(&&other: T)    -> T { ret self / other; }
+    pure fn modulo(&&other: T) -> T { ret self % other; }
+    pure fn neg()              -> T { ret -self;        }
+
+    pure fn to_int()         -> int { ret self as int; }
+    pure fn from_int(n: int) -> T   { ret n as T;      }
 }
 
 /**
diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs
index a89148ecec9..f74cbba23ce 100644
--- a/src/libstd/cmp.rs
+++ b/src/libstd/cmp.rs
@@ -2,24 +2,24 @@
 
 const fuzzy_epsilon: float = 1.0e-6;
 
-iface fuzzy_eq {
-    fn fuzzy_eq(&&other: self) -> bool;
+trait fuzzy_eq {
+    pure fn fuzzy_eq(&&other: self) -> bool;
 }
 
 impl fuzzy_eq of fuzzy_eq for float {
-    fn fuzzy_eq(&&other: float) -> bool {
+    pure fn fuzzy_eq(&&other: float) -> bool {
         ret float::abs(self - other) < fuzzy_epsilon;
     }
 }
 
 impl fuzzy_eq of fuzzy_eq for f32 {
-    fn fuzzy_eq(&&other: f32) -> bool {
+    pure fn fuzzy_eq(&&other: f32) -> bool {
         ret f32::abs(self - other) < (fuzzy_epsilon as f32);
     }
 }
 
 impl fuzzy_eq of fuzzy_eq for f64 {
-    fn fuzzy_eq(&&other: f64) -> bool {
+    pure fn fuzzy_eq(&&other: f64) -> bool {
         ret f64::abs(self - other) < (fuzzy_epsilon as f64);
     }
 }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index fb27724e369..4988adf9373 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -87,7 +87,7 @@ enum def {
     def_upvar(node_id /* local id of closed over var */,
               @def    /* closed over def */,
               node_id /* expr node that creates the closure */),
-    def_class(def_id),
+    def_class(def_id, bool /* has constructor */),
     def_region(node_id)
 }
 
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 37e8671facd..0cf593efdc3 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -53,7 +53,7 @@ pure fn def_id_of_def(d: def) -> def_id {
       def_fn(id, _) | def_mod(id) |
       def_foreign_mod(id) | def_const(id) |
       def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
-      def_use(id) | def_class(id) { id }
+      def_use(id) | def_class(id, _) { id }
       def_arg(id, _) | def_local(id, _) | def_self(id) |
       def_upvar(id, _, _) | def_binding(id) | def_region(id) {
         local_def(id)
diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs
index c9b35e561bb..f367fb63985 100644
--- a/src/libsyntax/ext/pipes/ast_builder.rs
+++ b/src/libsyntax/ext/pipes/ast_builder.rs
@@ -183,7 +183,6 @@ impl ast_builder of ext_ctxt_ast_builder for ext_ctxt {
         {mode: ast::infer(self.next_id()),
          ty: ty,
          ident: name,
-         // FIXME #2886: should this be the same as the infer id?
          id: self.next_id()}
     }
 
@@ -280,7 +279,6 @@ impl ast_builder of ext_ctxt_ast_builder for ext_ctxt {
     }
 
     fn ty_path_ast_builder(path: @ast::path) -> @ast::ty {
-        // FIXME #2886: make sure the node ids are legal.
         @{id: self.next_id(),
           node: ast::ty_path(path, self.next_id()),
           span: self.empty_span()}
diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs
index 52aa88e6cb6..a6734b285a1 100644
--- a/src/rustc/driver/driver.rs
+++ b/src/rustc/driver/driver.rs
@@ -14,6 +14,7 @@ import io::{reader_util, writer_util};
 import getopts::{optopt, optmulti, optflag, optflagopt, opt_present};
 import back::{x86, x86_64};
 import std::map::hashmap;
+import lib::llvm::llvm;
 
 enum pp_mode {ppm_normal, ppm_expanded, ppm_typed, ppm_identified,
               ppm_expanded_identified }
@@ -169,6 +170,9 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
                              session::sess_os_to_meta_os(sess.targ_cfg.os),
                              sess.opts.static));
 
+    time(time_passes, ~"language item collection", ||
+         middle::lang_items::collect_language_items(crate, sess));
+
     let { def_map: def_map,
           exp_map: exp_map,
           impl_map: impl_map,
@@ -440,6 +444,9 @@ fn build_session_options(match: getopts::match,
         }
         debugging_opts |= this_bit;
     }
+    if debugging_opts & session::debug_llvm != 0 {
+        llvm::LLVMSetDebug(1);
+    }
 
     let output_type =
         if parse_only || no_trans {
diff --git a/src/rustc/driver/session.rs b/src/rustc/driver/session.rs
index 64ae30895c4..61ef9f73c3f 100644
--- a/src/rustc/driver/session.rs
+++ b/src/rustc/driver/session.rs
@@ -40,6 +40,7 @@ const borrowck_stats: uint = 1024u;
 const borrowck_note_pure: uint = 2048;
 const borrowck_note_loan: uint = 4096;
 const no_landing_pads: uint = 8192;
+const debug_llvm: uint = 16384;
 
 fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
     ~[(~"ppregions", ~"prettyprint regions with \
@@ -61,7 +62,8 @@ fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
      (~"borrowck-note-loan", ~"note where loans are req'd",
       borrowck_note_loan),
      (~"no-landing-pads", ~"omit landing pads for unwinding",
-      no_landing_pads)
+      no_landing_pads),
+     (~"debug-llvm", ~"enable debug output from LLVM", debug_llvm)
     ]
 }
 
diff --git a/src/rustc/lib/llvm.rs b/src/rustc/lib/llvm.rs
index 376012dcf4e..7dbefa8e498 100644
--- a/src/rustc/lib/llvm.rs
+++ b/src/rustc/lib/llvm.rs
@@ -969,6 +969,9 @@ extern mod llvm {
 
     fn LLVMConstNamedStruct(S: TypeRef, ConstantVals: *ValueRef,
                             Count: c_uint) -> ValueRef;
+
+    /** Enables LLVM debug output. */
+    fn LLVMSetDebug(Enabled: c_int);
 }
 
 fn SetInstructionCallConv(Instr: ValueRef, CC: CallConv) {
diff --git a/src/rustc/metadata/csearch.rs b/src/rustc/metadata/csearch.rs
index 7f97583fe3d..0ba76c49246 100644
--- a/src/rustc/metadata/csearch.rs
+++ b/src/rustc/metadata/csearch.rs
@@ -25,6 +25,7 @@ export get_enum_variants;
 export get_impls_for_mod;
 export get_trait_methods;
 export get_method_names_if_trait;
+export get_item_attrs;
 export each_path;
 export get_type;
 export get_impl_traits;
@@ -149,6 +150,14 @@ fn get_method_names_if_trait(cstore: cstore::cstore, def: ast::def_id)
     ret decoder::get_method_names_if_trait(cdata, def.node);
 }
 
+fn get_item_attrs(cstore: cstore::cstore,
+                  def_id: ast::def_id,
+                  f: fn(~[@ast::meta_item])) {
+
+    let cdata = cstore::get_crate_data(cstore, def_id.crate);
+    decoder::get_item_attrs(cdata, def_id.node, f)
+}
+
 fn get_class_fields(tcx: ty::ctxt, def: ast::def_id) -> ~[ty::field_ty] {
     let cstore = tcx.cstore;
     let cdata = cstore::get_crate_data(cstore, def.crate);
diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs
index 3ff9ded3f1e..83684413641 100644
--- a/src/rustc/metadata/decoder.rs
+++ b/src/rustc/metadata/decoder.rs
@@ -39,6 +39,7 @@ export get_crate_vers;
 export get_impls_for_mod;
 export get_trait_methods;
 export get_method_names_if_trait;
+export get_item_attrs;
 export get_crate_module_paths;
 export def_like;
 export dl_def;
@@ -282,7 +283,8 @@ fn item_to_def_like(item: ebml::doc, did: ast::def_id, cnum: ast::crate_num)
     let fam_ch = item_family(item);
     alt fam_ch {
       'c' { dl_def(ast::def_const(did)) }
-      'C' { dl_def(ast::def_class(did)) }
+      'C' { dl_def(ast::def_class(did, true)) }
+      'S' { dl_def(ast::def_class(did, false)) }
       'u' { dl_def(ast::def_fn(did, ast::unsafe_fn)) }
       'f' { dl_def(ast::def_fn(did, ast::impure_fn)) }
       'p' { dl_def(ast::def_fn(did, ast::pure_fn)) }
@@ -659,6 +661,18 @@ fn get_method_names_if_trait(cdata: cmd, node_id: ast::node_id)
     ret some(resulting_method_names);
 }
 
+fn get_item_attrs(cdata: cmd,
+                  node_id: ast::node_id,
+                  f: fn(~[@ast::meta_item])) {
+
+    let item = lookup_item(node_id, cdata.data);
+    do ebml::tagged_docs(item, tag_attributes) |attributes| {
+        do ebml::tagged_docs(attributes, tag_attribute) |attribute| {
+            f(get_meta_items(attribute));
+        }
+    }
+}
+
 // Helper function that gets either fields or methods
 fn get_class_members(cdata: cmd, id: ast::node_id,
                      p: fn(char) -> bool) -> ~[ty::field_ty] {
@@ -694,7 +708,7 @@ fn family_has_type_params(fam_ch: char) -> bool {
     alt check fam_ch {
       'c' | 'T' | 'm' | 'n' | 'g' | 'h' | 'j' { false }
       'f' | 'u' | 'p' | 'F' | 'U' | 'P' | 'y' | 't' | 'v' | 'i' | 'I' | 'C'
-          | 'a'
+          | 'a' | 'S'
           { true }
     }
 }
@@ -738,6 +752,7 @@ fn item_family_to_str(fam: char) -> ~str {
       'i' { ret ~"impl"; }
       'I' { ret ~"trait"; }
       'C' { ret ~"class"; }
+      'S' { ret ~"struct"; }
       'g' { ret ~"public field"; }
       'j' { ret ~"private field"; }
     }
diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs
index b2847b3acc5..e1ed9fe396a 100644
--- a/src/rustc/metadata/encoder.rs
+++ b/src/rustc/metadata/encoder.rs
@@ -663,7 +663,16 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
         /* Now, make an item for the class itself */
         ebml_w.start_tag(tag_items_data_item);
         encode_def_id(ebml_w, local_def(item.id));
-        encode_family(ebml_w, 'C');
+
+        alt ctor {
+            none {
+                encode_family(ebml_w, 'S');
+            }
+            some(_) {
+                encode_family(ebml_w, 'C');
+            }
+        }
+
         encode_type_param_bounds(ebml_w, ecx, tps);
         encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
         encode_name(ebml_w, item.ident);
@@ -759,6 +768,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
         encode_type_param_bounds(ebml_w, ecx, tps);
         encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
         encode_name(ebml_w, item.ident);
+        encode_attributes(ebml_w, item.attrs);
         let mut i = 0u;
         for vec::each(*ty::trait_methods(tcx, local_def(item.id))) |mty| {
             alt ms[i] {
diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs
index 002b4d97e23..1f5f7c4518d 100644
--- a/src/rustc/middle/astencode.rs
+++ b/src/rustc/middle/astencode.rs
@@ -369,8 +369,8 @@ impl of tr for ast::def {
           ast::def_upvar(nid1, def, nid2) {
             ast::def_upvar(xcx.tr_id(nid1), @(*def).tr(xcx), xcx.tr_id(nid2))
           }
-          ast::def_class(did) {
-            ast::def_class(did.tr(xcx))
+          ast::def_class(did, has_constructor) {
+            ast::def_class(did.tr(xcx), has_constructor)
           }
           ast::def_region(nid) { ast::def_region(xcx.tr_id(nid)) }
         }
diff --git a/src/rustc/middle/borrowck/categorization.rs b/src/rustc/middle/borrowck/categorization.rs
index f5879145a9d..4088945e550 100644
--- a/src/rustc/middle/borrowck/categorization.rs
+++ b/src/rustc/middle/borrowck/categorization.rs
@@ -196,7 +196,7 @@ impl public_methods for borrowck_ctxt {
           ast::def_foreign_mod(_) | ast::def_const(_) |
           ast::def_use(_) | ast::def_variant(_, _) |
           ast::def_ty(_) | ast::def_prim_ty(_) |
-          ast::def_ty_param(_, _) | ast::def_class(_) |
+          ast::def_ty_param(_, _) | ast::def_class(_, _) |
           ast::def_region(_) {
             @{id:id, span:span,
               cat:cat_special(sk_static_item), lp:none,
diff --git a/src/rustc/middle/lang_items.rs b/src/rustc/middle/lang_items.rs
new file mode 100644
index 00000000000..2353da51f98
--- /dev/null
+++ b/src/rustc/middle/lang_items.rs
@@ -0,0 +1,209 @@
+// Detecting language items.
+//
+// Language items are items that represent concepts intrinsic to the language
+// itself. Examples are:
+//
+// * Traits that specify "kinds"; e.g. "const", "copy", "send".
+//
+// * Traits that represent operators; e.g. "add", "sub", "index".
+//
+// * Functions called by the compiler itself.
+
+import driver::session::session;
+import metadata::csearch::{each_path, get_item_attrs};
+import metadata::cstore::{iter_crate_data};
+import metadata::decoder::{dl_def, dl_field, dl_impl};
+import syntax::ast::{crate, def_id, def_ty, lit_str, meta_item, meta_list};
+import syntax::ast::{meta_name_value, meta_word};
+import syntax::ast_util::{local_def};
+import syntax::visit::{default_simple_visitor, mk_simple_visitor};
+import syntax::visit::{visit_crate, visit_item};
+
+import std::map::{hashmap, str_hash};
+import str_eq = str::eq;
+
+class LanguageItems {
+    let mut const_trait: option<def_id>;
+    let mut copy_trait: option<def_id>;
+    let mut send_trait: option<def_id>;
+    let mut owned_trait: option<def_id>;
+
+    let mut add_trait: option<def_id>;
+    let mut sub_trait: option<def_id>;
+    let mut mul_trait: option<def_id>;
+    let mut div_trait: option<def_id>;
+    let mut modulo_trait: option<def_id>;
+    let mut neg_trait: option<def_id>;
+    let mut bitops_trait: option<def_id>;
+    let mut index_trait: option<def_id>;
+
+    new() {
+        self.const_trait = none;
+        self.copy_trait = none;
+        self.send_trait = none;
+        self.owned_trait = none;
+
+        self.add_trait = none;
+        self.sub_trait = none;
+        self.mul_trait = none;
+        self.div_trait = none;
+        self.modulo_trait = none;
+        self.neg_trait = none;
+        self.bitops_trait = none;
+        self.index_trait = none;
+    }
+}
+
+class LanguageItemCollector {
+    let items: LanguageItems;
+
+    let crate: @crate;
+    let session: session;
+
+    let item_refs: hashmap<~str,&mut option<def_id>>;
+
+    new(crate: @crate, session: session) {
+        self.crate = crate;
+        self.session = session;
+
+        self.items = LanguageItems();
+
+        self.item_refs = str_hash();
+    }
+
+    // XXX: Needed to work around an issue with constructors.
+    fn init() {
+        self.item_refs.insert(~"const", &mut self.items.const_trait);
+        self.item_refs.insert(~"copy", &mut self.items.copy_trait);
+        self.item_refs.insert(~"send", &mut self.items.send_trait);
+        self.item_refs.insert(~"owned", &mut self.items.owned_trait);
+
+        self.item_refs.insert(~"add", &mut self.items.add_trait);
+        self.item_refs.insert(~"sub", &mut self.items.sub_trait);
+        self.item_refs.insert(~"mul", &mut self.items.mul_trait);
+        self.item_refs.insert(~"div", &mut self.items.div_trait);
+        self.item_refs.insert(~"modulo", &mut self.items.modulo_trait);
+        self.item_refs.insert(~"neg", &mut self.items.neg_trait);
+        self.item_refs.insert(~"bitops", &mut self.items.bitops_trait);
+        self.item_refs.insert(~"index", &mut self.items.index_trait);
+    }
+
+    fn match_and_collect_meta_item(item_def_id: def_id,
+                                   meta_item: meta_item) {
+
+        alt meta_item.node {
+            meta_name_value(key, literal) => {
+                alt literal.node {
+                    lit_str(value) => {
+                        self.match_and_collect_item(item_def_id,
+                                                    *key,
+                                                    *value);
+                    }
+                    _ => {
+                        // Skip.
+                    }
+                }
+            }
+            meta_word(*) | meta_list(*) {
+                // Skip.
+            }
+        }
+    }
+
+    fn match_and_collect_item(item_def_id: def_id, key: ~str, value: ~str) {
+        if !str_eq(key, ~"lang") {
+            ret;    // Didn't match.
+        }
+
+        alt self.item_refs.find(value) {
+            none => {
+                // Didn't match.
+            }
+            some(item_ref) => {
+                // Check for duplicates.
+                alt copy *item_ref {
+                    some(original_def_id)
+                            if original_def_id != item_def_id => {
+
+                        self.session.warn(#fmt("duplicate entry for `%s`",
+                                               value));
+                    }
+                    some(_) | none => {
+                        // OK.
+                    }
+                }
+
+                // Matched.
+                *item_ref = some(item_def_id);
+            }
+        }
+    }
+
+    fn collect_local_language_items() {
+        let this = unsafe { ptr::addr_of(self) };
+        visit_crate(*self.crate, (), mk_simple_visitor(@{
+            visit_item: |item| {
+                for item.attrs.each |attribute| {
+                    unsafe {
+                        (*this).match_and_collect_meta_item(local_def(item
+                                                                      .id),
+                                                            attribute.node
+                                                                     .value);
+                    }
+                }
+            }
+            with *default_simple_visitor()
+        }));
+    }
+
+    fn collect_external_language_items() {
+        let crate_store = self.session.cstore;
+        do iter_crate_data(crate_store) |crate_number, _crate_metadata| {
+            for each_path(crate_store, crate_number) |path_entry| {
+                let def_id;
+                alt path_entry.def_like {
+                    dl_def(def_ty(did)) => {
+                        def_id = did;
+                    }
+                    dl_def(_) | dl_impl(_) | dl_field {
+                        // Skip this.
+                        again;
+                    }
+                }
+
+                do get_item_attrs(crate_store, def_id) |meta_items| {
+                    for meta_items.each |meta_item| {
+                        self.match_and_collect_meta_item(def_id, *meta_item);
+                    }
+                }
+            }
+        }
+    }
+
+    fn check_completeness() {
+        for self.item_refs.each |key, item_ref| {
+            alt copy *item_ref {
+                none => {
+                    self.session.warn(#fmt("no item found for `%s`", key));
+                }
+                some(did) => {
+                    // OK.
+                }
+            }
+        }
+    }
+
+    fn collect() {
+        self.init();
+        self.collect_local_language_items();
+        self.collect_external_language_items();
+        self.check_completeness();
+    }
+}
+
+fn collect_language_items(crate: @crate, session: session) -> LanguageItems {
+    let collector = LanguageItemCollector(crate, session);
+    collector.collect();
+    copy collector.items
+}
+
diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs
index ca00aeaa0f4..cc6874bc967 100644
--- a/src/rustc/middle/region.rs
+++ b/src/rustc/middle/region.rs
@@ -467,7 +467,7 @@ fn determine_rp_in_ty(ty: @ast::ty,
     alt ty.node {
       ast::ty_path(_, id) {
         alt cx.def_map.get(id) {
-          ast::def_ty(did) | ast::def_class(did) {
+          ast::def_ty(did) | ast::def_class(did, _) {
             if did.crate == ast::local_crate {
                 cx.add_dep(did.node, cx.item_id);
             } else {
diff --git a/src/rustc/middle/resolve3.rs b/src/rustc/middle/resolve3.rs
index bddf83c429e..e75268cde7f 100644
--- a/src/rustc/middle/resolve3.rs
+++ b/src/rustc/middle/resolve3.rs
@@ -41,7 +41,7 @@ import syntax::visit::{visit_mod, visit_ty, vt};
 
 import box::ptr_eq;
 import dvec::{dvec, extensions};
-import option::get;
+import option::{get, is_some};
 import str::{connect, split_str};
 import vec::pop;
 
@@ -604,7 +604,7 @@ class Resolver {
     let unused_import_lint_level: level;
 
     let trait_info: hashmap<def_id,@hashmap<Atom,()>>;
-    let structs: hashmap<def_id,()>;
+    let structs: hashmap<def_id,bool>;
 
     // The number of imports that are currently unresolved.
     let mut unresolved_imports: uint;
@@ -926,7 +926,8 @@ class Resolver {
                 (*name_bindings).define_impl(impl_info);
 
                 // Record the def ID of this struct.
-                self.structs.insert(local_def(item.id), ());
+                self.structs.insert(local_def(item.id),
+                                    is_some(optional_ctor));
 
                 visit_item(item, new_parent, visitor);
             }
@@ -1378,12 +1379,16 @@ class Resolver {
 
                             (*child_name_bindings).define_type(def);
                         }
-                        def_class(def_id) {
+                        def_class(def_id, has_constructor) {
                             #debug("(building reduced graph for external \
-                                    crate) building value and type %s",
-                                    final_ident);
-                            (*child_name_bindings).define_value(def);
+                                    crate) building type %s (value? %d)",
+                                    final_ident,
+                                    if has_constructor { 1 } else { 0 });
                             (*child_name_bindings).define_type(def);
+
+                            if has_constructor {
+                                (*child_name_bindings).define_value(def);
+                            }
                         }
                         def_self(*) | def_arg(*) | def_local(*) |
                         def_prim_ty(*) | def_ty_param(*) | def_binding(*) |
@@ -4201,7 +4206,9 @@ class Resolver {
                     some(definition @ def_ty(class_id))
                             if self.structs.contains_key(class_id) {
 
-                        self.record_def(expr.id, def_class(class_id));
+                        let has_constructor = self.structs.get(class_id);
+                        let class_def = def_class(class_id, has_constructor);
+                        self.record_def(expr.id, class_def);
                     }
                     _ {
                         self.session.span_err(path.span,
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index b6b1873b1dc..465aeebe3af 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -2587,7 +2587,7 @@ fn type_err_to_str(cx: ctxt, err: type_err) -> ~str {
 
 fn def_has_ty_params(def: ast::def) -> bool {
     alt def {
-      ast::def_fn(_, _) | ast::def_variant(_, _) | ast::def_class(_)
+      ast::def_fn(_, _) | ast::def_variant(_, _) | ast::def_class(_, _)
         { true }
       _ { false }
     }
diff --git a/src/rustc/middle/typeck/astconv.rs b/src/rustc/middle/typeck/astconv.rs
index ebd189a15b7..3baea12ab48 100644
--- a/src/rustc/middle/typeck/astconv.rs
+++ b/src/rustc/middle/typeck/astconv.rs
@@ -270,7 +270,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy owned>(
                                                        path_to_str(path))); }
           some(d) { d }};
         alt a_def {
-          ast::def_ty(did) | ast::def_class(did) {
+          ast::def_ty(did) | ast::def_class(did, _) {
             ast_path_to_ty(self, rscope, did, path, id).ty
           }
           ast::def_prim_ty(nty) {
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index 0b78fd1a505..eaf0e90b26d 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -1649,7 +1649,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         // Resolve the path.
         let class_id;
         alt tcx.def_map.find(id) {
-            some(ast::def_class(type_def_id)) => {
+            some(ast::def_class(type_def_id, _)) => {
                 class_id = type_def_id;
             }
             _ => {
@@ -2160,7 +2160,7 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
       }
 
       ast::def_fn(id, _) | ast::def_const(id) |
-      ast::def_variant(_, id) | ast::def_class(id) {
+      ast::def_variant(_, id) | ast::def_class(id, _) {
         ret ty::lookup_item_type(fcx.ccx.tcx, id);
       }
       ast::def_binding(nid) {
diff --git a/src/rustc/middle/typeck/check/regionmanip.rs b/src/rustc/middle/typeck/check/regionmanip.rs
index 2231d9b320a..d1052fd6a2a 100644
--- a/src/rustc/middle/typeck/check/regionmanip.rs
+++ b/src/rustc/middle/typeck/check/regionmanip.rs
@@ -200,7 +200,7 @@ fn region_of(fcx: @fn_ctxt, expr: @ast::expr) -> ty::region {
           ast::def_foreign_mod(_) | ast::def_const(_) |
           ast::def_use(_) | ast::def_variant(_, _) |
           ast::def_ty(_) | ast::def_prim_ty(_) |
-          ast::def_ty_param(_, _) | ast::def_class(_) |
+          ast::def_ty_param(_, _) | ast::def_class(_, _) |
           ast::def_region(_) {
             ty::re_static
           }
diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc
index 406c46cc6c6..b2cce508e57 100644
--- a/src/rustc/rustc.rc
+++ b/src/rustc/rustc.rc
@@ -88,6 +88,7 @@ mod middle {
     mod region;
     mod const_eval;
     mod astencode;
+    mod lang_items;
 }
 
 mod front {
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index a9f759b26aa..4a927744f07 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -27,6 +27,7 @@
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Target/TargetOptions.h"
 #include "llvm/Support/Host.h"
+#include "llvm/Support/Debug.h"
 #include "llvm-c/Core.h"
 #include "llvm-c/BitReader.h"
 #include "llvm-c/Object.h"
@@ -185,3 +186,7 @@ extern "C" LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef B,
                                            unwrap(target), unwrap(source),
                                            order));
 }
+
+extern "C" void LLVMSetDebug(int Enabled) {
+  DebugFlag = Enabled;
+}
diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in
index f3a3d7f4f23..64b560999be 100644
--- a/src/rustllvm/rustllvm.def.in
+++ b/src/rustllvm/rustllvm.def.in
@@ -528,6 +528,7 @@ LLVMSetAlignment
 LLVMSetCleanup
 LLVMSetCurrentDebugLocation
 LLVMSetDataLayout
+LLVMSetDebug
 LLVMSetFunctionCallConv
 LLVMSetGC
 LLVMSetGlobalConstant
diff --git a/src/test/compile-fail/not-utf8.bin b/src/test/compile-fail/not-utf8.bin
new file mode 100644
index 00000000000..4148e5b88fe
--- /dev/null
+++ b/src/test/compile-fail/not-utf8.bin
Binary files differdiff --git a/src/test/compile-fail/not-utf8.rs b/src/test/compile-fail/not-utf8.rs
new file mode 100644
index 00000000000..2038f139359
--- /dev/null
+++ b/src/test/compile-fail/not-utf8.rs
@@ -0,0 +1,5 @@
+// error-pattern: is not UTF-8
+
+fn foo() {
+    #include("not-utf8.bin")
+}
diff --git a/src/test/run-pass/issue-3029.rs b/src/test/run-pass/issue-3029.rs
new file mode 100644
index 00000000000..352ada202e2
--- /dev/null
+++ b/src/test/run-pass/issue-3029.rs
@@ -0,0 +1,8 @@
+// xfail-test
+fn fail_then_concat() {
+    let x = ~[], y = ~[3];
+    fail;
+    x += y;
+    ~"good" + ~"bye";
+}
+
diff --git a/src/test/run-pass/issue-868.rs b/src/test/run-pass/issue-868.rs
new file mode 100644
index 00000000000..dcc8c4e08db
--- /dev/null
+++ b/src/test/run-pass/issue-868.rs
@@ -0,0 +1,15 @@
+fn f<T>(g: fn() -> T) -> T { g() }
+
+fn main() {
+  let _x = f( | | { 10 });
+    // used to be: cannot determine a type for this expression
+    f(| | { });
+    // ditto
+    f( | | { ()});
+    // always worked
+    let _: () = f(| | { });
+    // empty block with no type info should compile too
+    let _ = f(||{});
+    let _ = (||{});
+}
+
diff --git a/src/test/run-pass/task-comm-0.rs b/src/test/run-pass/task-comm-0.rs
index 532daf3651c..eb866ee7b3e 100644
--- a/src/test/run-pass/task-comm-0.rs
+++ b/src/test/run-pass/task-comm-0.rs
@@ -1,31 +1,29 @@
 use std;
 
-import comm;
-import comm::chan;
-import comm::send;
+import pipes;
+import pipes::chan;
+import pipes::port;
 import task;
 
 fn main() { test05(); }
 
 fn test05_start(ch : chan<int>) {
-    log(error, ch);
-    send(ch, 10);
+    ch.send(10);
     #error("sent 10");
-    send(ch, 20);
+    ch.send(20);
     #error("sent 20");
-    send(ch, 30);
+    ch.send(30);
     #error("sent 30");
 }
 
 fn test05() {
-    let po = comm::port();
-    let ch = comm::chan(po);
+    let (ch, po) = pipes::stream();
     task::spawn(|| test05_start(ch) );
-    let mut value = comm::recv(po);
+    let mut value = po.recv();
     log(error, value);
-    value = comm::recv(po);
+    value = po.recv();
     log(error, value);
-    value = comm::recv(po);
+    value = po.recv();
     log(error, value);
     assert (value == 30);
 }
diff --git a/src/test/run-pass/task-comm-10.rs b/src/test/run-pass/task-comm-10.rs
index 1d0963a29dc..ef94a13c072 100644
--- a/src/test/run-pass/task-comm-10.rs
+++ b/src/test/run-pass/task-comm-10.rs
@@ -1,28 +1,27 @@
 use std;
 import task;
-import comm;
+import pipes;
 
-fn start(c: comm::chan<comm::chan<~str>>) {
-    let p = comm::port();
-    comm::send(c, comm::chan(p));
+fn start(c: pipes::chan<pipes::chan<~str>>) {
+    let (ch, p) = pipes::stream();
+    c.send(ch);
 
     let mut a;
     let mut b;
-    a = comm::recv(p);
+    a = p.recv();
     assert a == ~"A";
     log(error, a);
-    b = comm::recv(p);
+    b = p.recv();
     assert b == ~"B";
     log(error, b);
 }
 
 fn main() {
-    let p = comm::port();
-    let ch = comm::chan(p);
+    let (ch, p) = pipes::stream();
     let child = task::spawn(|| start(ch) );
 
-    let c = comm::recv(p);
-    comm::send(c, ~"A");
-    comm::send(c, ~"B");
+    let c = p.recv();
+    c.send(~"A");
+    c.send(~"B");
     task::yield();
 }
diff --git a/src/test/run-pass/task-comm-11.rs b/src/test/run-pass/task-comm-11.rs
index f96f9d148d0..5e1e5c5facd 100644
--- a/src/test/run-pass/task-comm-11.rs
+++ b/src/test/run-pass/task-comm-11.rs
@@ -1,15 +1,14 @@
 use std;
-import comm;
+import pipes;
 import task;
 
-fn start(c: comm::chan<comm::chan<int>>) {
-    let p: comm::port<int> = comm::port();
-    comm::send(c, comm::chan(p));
+fn start(c: pipes::chan<pipes::chan<int>>) {
+    let (ch, p) = pipes::stream();
+    c.send(ch);
 }
 
 fn main() {
-    let p = comm::port();
-    let ch = comm::chan(p);
+    let (ch, p) = pipes::stream();
     let child = task::spawn(|| start(ch) );
-    let c = comm::recv(p);
+    let c = p.recv();
 }
diff --git a/src/test/run-pass/task-comm-13.rs b/src/test/run-pass/task-comm-13.rs
index 3ded4aac5ae..88220437c43 100644
--- a/src/test/run-pass/task-comm-13.rs
+++ b/src/test/run-pass/task-comm-13.rs
@@ -1,17 +1,16 @@
 use std;
 import task;
-import comm;
-import comm::send;
+import pipes;
+import pipes::send;
 
-fn start(c: comm::chan<int>, start: int, number_of_messages: int) {
+fn start(c: pipes::chan<int>, start: int, number_of_messages: int) {
     let mut i: int = 0;
-    while i < number_of_messages { send(c, start + i); i += 1; }
+    while i < number_of_messages { c.send(start + i); i += 1; }
 }
 
 fn main() {
     #debug("Check that we don't deadlock.");
-    let p = comm::port::<int>();
-    let ch = comm::chan(p);
+    let (ch, p) = pipes::stream();
     task::try(|| start(ch, 0, 10) );
     #debug("Joined task");
 }
diff --git a/src/test/run-pass/task-comm-14.rs b/src/test/run-pass/task-comm-14.rs
index ef9c4ae5010..268b6d06dfd 100644
--- a/src/test/run-pass/task-comm-14.rs
+++ b/src/test/run-pass/task-comm-14.rs
@@ -1,15 +1,14 @@
-use std;
-import comm;
 import task;
 
 fn main() {
-    let po = comm::port::<int>();
-    let ch = comm::chan(po);
+    let po = pipes::port_set();
 
     // Spawn 10 tasks each sending us back one int.
     let mut i = 10;
     while (i > 0) {
         log(debug, i);
+        let (ch, p) = pipes::stream();
+        po.add(p);
         task::spawn(|copy i| child(i, ch) );
         i = i - 1;
     }
@@ -18,17 +17,16 @@ fn main() {
     // anything back, so we deadlock here.
 
     i = 10;
-    let mut value = 0;
     while (i > 0) {
         log(debug, i);
-        value = comm::recv(po);
+        po.recv();
         i = i - 1;
     }
 
     #debug("main thread exiting");
 }
 
-fn child(x: int, ch: comm::chan<int>) {
+fn child(x: int, ch: pipes::chan<int>) {
     log(debug, x);
-    comm::send(ch, copy x);
+    ch.send(x);
 }
diff --git a/src/test/run-pass/task-comm-15.rs b/src/test/run-pass/task-comm-15.rs
index d9291fd6898..71a732490ce 100644
--- a/src/test/run-pass/task-comm-15.rs
+++ b/src/test/run-pass/task-comm-15.rs
@@ -1,23 +1,21 @@
 // xfail-win32
 use std;
-import comm;
 import task;
 
-fn start(c: comm::chan<int>, i0: int) {
+fn start(c: pipes::chan<int>, i0: int) {
     let mut i = i0;
     while i > 0 {
-        comm::send(c, 0);
+        c.send(0);
         i = i - 1;
     }
 }
 
 fn main() {
-    let p = comm::port();
     // Spawn a task that sends us back messages. The parent task
     // is likely to terminate before the child completes, so from
     // the child's point of view the receiver may die. We should
     // drop messages on the floor in this case, and not crash!
-    let ch = comm::chan(p);
-    let child = task::spawn(|| start(ch, 10) );
-    let c = comm::recv(p);
+    let (ch, p) = pipes::stream();
+    task::spawn(|| start(ch, 10));
+    p.recv();
 }
diff --git a/src/test/run-pass/task-comm-16.rs b/src/test/run-pass/task-comm-16.rs
index bc46de64cd7..2d1c72df713 100644
--- a/src/test/run-pass/task-comm-16.rs
+++ b/src/test/run-pass/task-comm-16.rs
@@ -1,44 +1,41 @@
 // -*- rust -*-
 
 use std;
-import comm;
-import comm::send;
-import comm::port;
-import comm::recv;
-import comm::chan;
+import pipes;
+import pipes::send;
+import pipes::port;
+import pipes::recv;
+import pipes::chan;
 
 // Tests of ports and channels on various types
 fn test_rec() {
     type r = {val0: int, val1: u8, val2: char};
 
-    let po = comm::port();
-    let ch = chan(po);
+    let (ch, po) = pipes::stream();
     let r0: r = {val0: 0, val1: 1u8, val2: '2'};
-    send(ch, r0);
+    ch.send(r0);
     let mut r1: r;
-    r1 = recv(po);
+    r1 = po.recv();
     assert (r1.val0 == 0);
     assert (r1.val1 == 1u8);
     assert (r1.val2 == '2');
 }
 
 fn test_vec() {
-    let po = port();
-    let ch = chan(po);
+    let (ch, po) = pipes::stream();
     let v0: ~[int] = ~[0, 1, 2];
-    send(ch, v0);
-    let v1 = recv(po);
+    ch.send(v0);
+    let v1 = po.recv();
     assert (v1[0] == 0);
     assert (v1[1] == 1);
     assert (v1[2] == 2);
 }
 
 fn test_str() {
-    let po = port();
-    let ch = chan(po);
-    let s0 = ~"test";
-    send(ch, s0);
-    let s1 = recv(po);
+    let (ch, po) = pipes::stream();
+    let s0 = "test";
+    ch.send(s0);
+    let s1 = po.recv();
     assert (s1[0] == 't' as u8);
     assert (s1[1] == 'e' as u8);
     assert (s1[2] == 's' as u8);
@@ -47,33 +44,36 @@ fn test_str() {
 
 fn test_tag() {
     enum t { tag1, tag2(int), tag3(int, u8, char), }
-    let po = port();
-    let ch = chan(po);
-    send(ch, tag1);
-    send(ch, tag2(10));
-    send(ch, tag3(10, 11u8, 'A'));
+    let (ch, po) = pipes::stream();
+    ch.send(tag1);
+    ch.send(tag2(10));
+    ch.send(tag3(10, 11u8, 'A'));
     let mut t1: t;
-    t1 = recv(po);
+    t1 = po.recv();
     assert (t1 == tag1);
-    t1 = recv(po);
+    t1 = po.recv();
     assert (t1 == tag2(10));
-    t1 = recv(po);
+    t1 = po.recv();
     assert (t1 == tag3(10, 11u8, 'A'));
 }
 
 fn test_chan() {
-    let po = port();
-    let ch = chan(po);
-    let po0 = port();
-    let ch0 = chan(po0);
-    send(ch, ch0);
-    let ch1 = recv(po);
+    let (ch, po) = pipes::stream();
+    let (ch0, po0) = pipes::stream();
+    ch.send(ch0);
+    let ch1 = po.recv();
     // Does the transmitted channel still work?
 
-    send(ch1, 10);
+    ch1.send(10);
     let mut i: int;
-    i = recv(po0);
+    i = po0.recv();
     assert (i == 10);
 }
 
-fn main() { test_rec(); test_vec(); test_str(); test_tag(); test_chan(); }
+fn main() {
+    test_rec();
+    test_vec();
+    test_str();
+    test_tag();
+    test_chan();
+}
diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs
index c03db442022..05c057d85fd 100644
--- a/src/test/run-pass/task-comm-3.rs
+++ b/src/test/run-pass/task-comm-3.rs
@@ -1,9 +1,9 @@
 use std;
 import task;
-import comm;
-import comm::chan;
-import comm::send;
-import comm::recv;
+import pipes;
+import pipes::chan;
+import pipes::send;
+import pipes::recv;
 
 fn main() { #debug("===== WITHOUT THREADS ====="); test00(); }
 
@@ -12,7 +12,7 @@ fn test00_start(ch: chan<int>, message: int, count: int) {
     let mut i: int = 0;
     while i < count {
         #debug("Sending Message");
-        send(ch, message + 0);
+        ch.send(message + 0);
         i = i + 1;
     }
     #debug("Ending test00_start");
@@ -24,14 +24,14 @@ fn test00() {
 
     #debug("Creating tasks");
 
-    let po = comm::port();
-    let ch = chan(po);
+    let po = pipes::port_set();
 
     let mut i: int = 0;
 
     // Create and spawn tasks...
     let mut results = ~[];
     while i < number_of_tasks {
+        let ch = po.chan();        
         do task::task().future_result(|-r| {
             results += ~[r];
         }).spawn |copy i| {
@@ -45,7 +45,7 @@ fn test00() {
     for results.each |r| {
         i = 0;
         while i < number_of_messages {
-            let value = recv(po);
+            let value = po.recv();
             sum += value;
             i = i + 1;
         }
diff --git a/src/test/run-pass/task-comm-4.rs b/src/test/run-pass/task-comm-4.rs
index f7de33c63d6..9b99c1cb799 100644
--- a/src/test/run-pass/task-comm-4.rs
+++ b/src/test/run-pass/task-comm-4.rs
@@ -1,44 +1,43 @@
 use std;
-import comm;
-import comm::send;
+import pipes;
+import pipes::send;
 
 fn main() { test00(); }
 
 fn test00() {
     let mut r: int = 0;
     let mut sum: int = 0;
-    let p = comm::port();
-    let c = comm::chan(p);
-    send(c, 1);
-    send(c, 2);
-    send(c, 3);
-    send(c, 4);
-    r = comm::recv(p);
+    let (c, p) = pipes::stream();
+    c.send(1);
+    c.send(2);
+    c.send(3);
+    c.send(4);
+    r = p.recv();
     sum += r;
     log(debug, r);
-    r = comm::recv(p);
+    r = p.recv();
     sum += r;
     log(debug, r);
-    r = comm::recv(p);
+    r = p.recv();
     sum += r;
     log(debug, r);
-    r = comm::recv(p);
+    r = p.recv();
     sum += r;
     log(debug, r);
-    send(c, 5);
-    send(c, 6);
-    send(c, 7);
-    send(c, 8);
-    r = comm::recv(p);
+    c.send(5);
+    c.send(6);
+    c.send(7);
+    c.send(8);
+    r = p.recv();
     sum += r;
     log(debug, r);
-    r = comm::recv(p);
+    r = p.recv();
     sum += r;
     log(debug, r);
-    r = comm::recv(p);
+    r = p.recv();
     sum += r;
     log(debug, r);
-    r = comm::recv(p);
+    r = p.recv();
     sum += r;
     log(debug, r);
     assert (sum == 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8);
diff --git a/src/test/run-pass/task-comm-5.rs b/src/test/run-pass/task-comm-5.rs
index a0d4f4595be..249bdaf1c9a 100644
--- a/src/test/run-pass/task-comm-5.rs
+++ b/src/test/run-pass/task-comm-5.rs
@@ -1,17 +1,16 @@
 use std;
-import comm;
+import pipes;
 
 fn main() { test00(); }
 
 fn test00() {
     let r: int = 0;
     let mut sum: int = 0;
-    let p = comm::port();
-    let c = comm::chan(p);
+    let (c, p) = pipes::stream();
     let number_of_messages: int = 1000;
     let mut i: int = 0;
-    while i < number_of_messages { comm::send(c, i + 0); i += 1; }
+    while i < number_of_messages { c.send(i + 0); i += 1; }
     i = 0;
-    while i < number_of_messages { sum += comm::recv(p); i += 1; }
+    while i < number_of_messages { sum += p.recv(); i += 1; }
     assert (sum == number_of_messages * (number_of_messages - 1) / 2);
 }
diff --git a/src/test/run-pass/task-comm-6.rs b/src/test/run-pass/task-comm-6.rs
index b363b25e864..8bc93a78913 100644
--- a/src/test/run-pass/task-comm-6.rs
+++ b/src/test/run-pass/task-comm-6.rs
@@ -1,37 +1,37 @@
 use std;
-import comm;
-import comm::send;
-import comm::chan;
-import comm::recv;
+import pipes;
+import pipes::send;
+import pipes::chan;
+import pipes::recv;
 
 fn main() { test00(); }
 
 fn test00() {
     let mut r: int = 0;
     let mut sum: int = 0;
-    let p = comm::port();
-    let c0 = chan(p);
-    let c1 = chan(p);
-    let c2 = chan(p);
-    let c3 = chan(p);
+    let p = pipes::port_set();
+    let c0 = p.chan();
+    let c1 = p.chan();
+    let c2 = p.chan();
+    let c3 = p.chan();
     let number_of_messages: int = 1000;
     let mut i: int = 0;
     while i < number_of_messages {
-        send(c0, i + 0);
-        send(c1, i + 0);
-        send(c2, i + 0);
-        send(c3, i + 0);
+        c0.send(i + 0);
+        c1.send(i + 0);
+        c2.send(i + 0);
+        c3.send(i + 0);
         i += 1;
     }
     i = 0;
     while i < number_of_messages {
-        r = recv(p);
+        r = p.recv();
         sum += r;
-        r = recv(p);
+        r = p.recv();
         sum += r;
-        r = recv(p);
+        r = p.recv();
         sum += r;
-        r = recv(p);
+        r = p.recv();
         sum += r;
         i += 1;
     }
diff --git a/src/test/run-pass/task-comm-7.rs b/src/test/run-pass/task-comm-7.rs
index b8922400777..1df3de6ba1e 100644
--- a/src/test/run-pass/task-comm-7.rs
+++ b/src/test/run-pass/task-comm-7.rs
@@ -1,43 +1,45 @@
 use std;
 import task;
-import comm;
 
 fn main() { test00(); }
 
-fn test00_start(c: comm::chan<int>, start: int, number_of_messages: int) {
+fn test00_start(c: pipes::chan<int>, start: int, number_of_messages: int) {
     let mut i: int = 0;
-    while i < number_of_messages { comm::send(c, start + i); i += 1; }
+    while i < number_of_messages { c.send(start + i); i += 1; }
 }
 
 fn test00() {
     let mut r: int = 0;
     let mut sum: int = 0;
-    let p = comm::port();
+    let p = pipes::port_set();
     let number_of_messages: int = 10;
-    let c = comm::chan(p);
 
+    let c = p.chan();
     do task::spawn {
         test00_start(c, number_of_messages * 0, number_of_messages);
     }
+    let c = p.chan();
     do task::spawn {
         test00_start(c, number_of_messages * 1, number_of_messages);
     }
+    let c = p.chan();
     do task::spawn {
         test00_start(c, number_of_messages * 2, number_of_messages);
     }
+    let c = p.chan();
     do task::spawn {
         test00_start(c, number_of_messages * 3, number_of_messages);
     }
 
     let mut i: int = 0;
     while i < number_of_messages {
-        r = comm::recv(p);
+        r = p.recv();
         sum += r;
-        r = comm::recv(p);
+        r = p.recv();
         sum += r;
-        r = comm::recv(p);
+        r = p.recv();
         sum += r;
-        r = comm::recv(p);
+        r = p.recv();
         sum += r;
         i += 1;
     }
diff --git a/src/test/run-pass/task-comm-9.rs b/src/test/run-pass/task-comm-9.rs
index 964029dee20..939cfd15797 100644
--- a/src/test/run-pass/task-comm-9.rs
+++ b/src/test/run-pass/task-comm-9.rs
@@ -1,20 +1,19 @@
 use std;
 import task;
-import comm;
 
 fn main() { test00(); }
 
-fn test00_start(c: comm::chan<int>, number_of_messages: int) {
+fn test00_start(c: pipes::chan<int>, number_of_messages: int) {
     let mut i: int = 0;
-    while i < number_of_messages { comm::send(c, i + 0); i += 1; }
+    while i < number_of_messages { c.send(i + 0); i += 1; }
 }
 
 fn test00() {
     let r: int = 0;
     let mut sum: int = 0;
-    let p = comm::port();
+    let p = pipes::port_set();
     let number_of_messages: int = 10;
-    let ch = comm::chan(p);
+    let ch = p.chan();
 
     let mut result = none;
     do task::task().future_result(|-r| { result = some(r); }).spawn {
@@ -23,7 +22,7 @@ fn test00() {
 
     let mut i: int = 0;
     while i < number_of_messages {
-        sum += comm::recv(p);
+        sum += p.recv();
         log(debug, r);
         i += 1;
     }
diff --git a/src/test/run-pass/trivial-message.rs b/src/test/run-pass/trivial-message.rs
index 487b440ee42..ab3efd6b22e 100644
--- a/src/test/run-pass/trivial-message.rs
+++ b/src/test/run-pass/trivial-message.rs
@@ -1,14 +1,12 @@
-use std;
-import comm::*;
+import pipes::{port, chan};
 
 /*
   This is about the simplest program that can successfully send a
   message.
  */
 fn main() {
-    let po = port();
-    let ch = chan(po);
-    send(ch, 42);
-    let r = recv(po);
+    let (ch, po) = pipes::stream();
+    ch.send(42);
+    let r = po.recv();
     log(error, r);
 }
diff --git a/src/test/run-pass/unreachable-code.rs b/src/test/run-pass/unreachable-code.rs
new file mode 100644
index 00000000000..0d1a4991751
--- /dev/null
+++ b/src/test/run-pass/unreachable-code.rs
@@ -0,0 +1,31 @@
+// xfail-pretty
+
+fn id(x: bool) -> bool { x }
+
+fn call_id() {
+    let c <- fail;
+    id(c);
+}
+
+fn call_id_2() { id(true) && id(ret); }
+
+fn call_id_3() { id(ret) && id(ret); }
+
+fn log_fail() { log(error, fail); }
+
+fn log_ret() { log(error, ret); }
+
+fn log_break() { loop { log(error, break); } }
+
+fn log_again() { loop { log(error, again); } }
+
+fn ret_ret() -> int { ret (ret 2) + 3; }
+
+fn ret_guard() {
+    alt 2 {
+      x if (ret) { x; }
+      _ {}
+    }
+}
+
+fn main() {}