about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-12-27 13:11:48 +0000
committerbors <bors@rust-lang.org>2014-12-27 13:11:48 +0000
commit4a4c89c7a4a763c253a97ff04647f52aca6a5490 (patch)
treee7d313c7ebc0418284ea65089db287cca633bc99
parent9be54be15b4b4ba5c1b22d958d7619a5154ab469 (diff)
parent1a73ccc8db0a10e82632808e058645f2d6fa0095 (diff)
downloadrust-4a4c89c7a4a763c253a97ff04647f52aca6a5490.tar.gz
rust-4a4c89c7a4a763c253a97ff04647f52aca6a5490.zip
auto merge of #20119 : FlaPer87/rust/oibit-send-and-friends, r=nikomatsakis
More work on opt-in built in traits. `Send` and `Sync` are not opt-in, `OwnedPtr` renamed to `UniquePtr` and the `Send` and `Sync` traits are now unsafe.

NOTE: This likely needs to be rebased on top of the yet-to-land snapshot.

r? @nikomatsakis 

cc #13231 
-rw-r--r--src/liballoc/arc.rs13
-rw-r--r--src/liballoc/boxed.rs3
-rw-r--r--src/libcollections/dlist.rs2
-rw-r--r--src/libcollections/vec.rs54
-rw-r--r--src/libcore/atomic.rs10
-rw-r--r--src/libcore/kinds.rs4
-rw-r--r--src/libcore/ptr.rs33
-rw-r--r--src/libflate/lib.rs9
-rw-r--r--src/librustc/diagnostics.rs3
-rw-r--r--src/librustc/middle/check_static.rs20
-rw-r--r--src/librustc/middle/mem_categorization.rs14
-rw-r--r--src/librustc/middle/traits/error_reporting.rs349
-rw-r--r--src/librustc/middle/traits/fulfill.rs6
-rw-r--r--src/librustc/middle/traits/mod.rs16
-rw-r--r--src/librustc/middle/traits/select.rs95
-rw-r--r--src/librustc/middle/traits/util.rs2
-rw-r--r--src/librustc/middle/ty_fold.rs2
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs12
-rw-r--r--src/librustc_borrowck/borrowck/fragments.rs4
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs2
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/lifetime.rs4
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/restrictions.rs2
-rw-r--r--src/librustc_trans/back/write.rs2
-rw-r--r--src/librustc_trans/trans/debuginfo.rs26
-rw-r--r--src/librustc_trans/trans/mod.rs3
-rw-r--r--src/librustc_typeck/check/regionck.rs6
-rw-r--r--src/librustc_typeck/check/vtable.rs281
-rw-r--r--src/librustc_typeck/check/wf.rs20
-rw-r--r--src/libstd/c_str.rs6
-rw-r--r--src/libstd/c_vec.rs8
-rw-r--r--src/libstd/collections/hash/table.rs20
-rw-r--r--src/libstd/comm/blocking.rs4
-rw-r--r--src/libstd/comm/mod.rs60
-rw-r--r--src/libstd/comm/mpsc_queue.rs3
-rw-r--r--src/libstd/comm/spsc_queue.rs4
-rw-r--r--src/libstd/comm/sync.rs8
-rw-r--r--src/libstd/io/buffered.rs6
-rw-r--r--src/libstd/io/stdio.rs41
-rw-r--r--src/libstd/rt/exclusive.rs4
-rw-r--r--src/libstd/sync/barrier.rs7
-rw-r--r--src/libstd/sync/condvar.rs6
-rw-r--r--src/libstd/sync/mutex.rs27
-rw-r--r--src/libstd/sync/once.rs3
-rw-r--r--src/libstd/sync/rwlock.rs6
-rw-r--r--src/libstd/sys/common/helper_thread.rs13
-rw-r--r--src/libstd/sys/common/mutex.rs3
-rw-r--r--src/libstd/sys/unix/c.rs6
-rw-r--r--src/libstd/sys/unix/mutex.rs3
-rw-r--r--src/libstd/sys/unix/pipe.rs9
-rw-r--r--src/libstd/sys/unix/stack_overflow.rs2
-rw-r--r--src/libstd/sys/unix/tcp.rs4
-rw-r--r--src/libstd/sys/windows/mutex.rs2
-rw-r--r--src/libstd/sys/windows/pipe.rs12
-rw-r--r--src/libstd/sys/windows/tcp.rs12
-rw-r--r--src/libstd/sys/windows/timer.rs3
-rw-r--r--src/libstd/thread.rs23
-rw-r--r--src/libstd/thread_local/mod.rs4
-rw-r--r--src/libstd/thread_local/scoped.rs5
-rw-r--r--src/libsyntax/ext/deriving/bounds.rs7
-rw-r--r--src/libtest/lib.rs2
-rw-r--r--src/test/bench/shootout-reverse-complement.rs17
-rw-r--r--src/test/bench/shootout-spectralnorm.rs13
-rw-r--r--src/test/compile-fail/deriving-bounds.rs6
-rw-r--r--src/test/compile-fail/issue-17718-static-sync.rs2
-rw-r--r--src/test/compile-fail/issue-7013.rs1
-rw-r--r--src/test/compile-fail/issue-7364.rs4
-rw-r--r--src/test/compile-fail/kindck-destructor-owned.rs13
-rw-r--r--src/test/compile-fail/kindck-nonsendable-1.rs4
-rw-r--r--src/test/compile-fail/kindck-send-unsafe.rs9
-rw-r--r--src/test/compile-fail/mut-not-freeze.rs5
-rw-r--r--src/test/compile-fail/no-send-res-ports.rs1
-rw-r--r--src/test/compile-fail/no_send-rc.rs1
-rw-r--r--src/test/compile-fail/no_share-rc.rs1
-rw-r--r--src/test/compile-fail/regions-bounded-by-send.rs20
-rw-r--r--src/test/compile-fail/task-rng-isnt-sendable.rs1
-rw-r--r--src/test/compile-fail/typeck-unsafe-always-share.rs3
-rw-r--r--src/test/compile-fail/unique-unique-kind.rs4
-rw-r--r--src/test/compile-fail/unsendable-class.rs4
-rw-r--r--src/test/run-pass/const-block.rs4
-rw-r--r--src/test/run-pass/const-cast-ptr-int.rs10
-rw-r--r--src/test/run-pass/const-cast.rs14
-rw-r--r--src/test/run-pass/deriving-bounds.rs2
-rw-r--r--src/test/run-pass/issue-13837.rs8
-rw-r--r--src/test/run-pass/issue-17718-static-unsafe-interior.rs24
-rw-r--r--src/test/run-pass/issue-2718.rs8
-rw-r--r--src/test/run-pass/typeck_type_placeholder_1.rs9
86 files changed, 975 insertions, 533 deletions
diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs
index 893c9d250b7..8d8bbb42932 100644
--- a/src/liballoc/arc.rs
+++ b/src/liballoc/arc.rs
@@ -117,6 +117,10 @@ pub struct Arc<T> {
     _ptr: *mut ArcInner<T>,
 }
 
+unsafe impl<T: Sync + Send> Send for Arc<T> { }
+unsafe impl<T: Sync + Send> Sync for Arc<T> { }
+
+
 /// A weak pointer to an `Arc`.
 ///
 /// Weak pointers will not keep the data inside of the `Arc` alive, and can be used to break cycles
@@ -129,13 +133,19 @@ pub struct Weak<T> {
     _ptr: *mut ArcInner<T>,
 }
 
+unsafe impl<T: Sync + Send> Send for Weak<T> { }
+unsafe impl<T: Sync + Send> Sync for Weak<T> { }
+
 struct ArcInner<T> {
     strong: atomic::AtomicUint,
     weak: atomic::AtomicUint,
     data: T,
 }
 
-impl<T: Sync + Send> Arc<T> {
+unsafe impl<T: Sync + Send> Send for ArcInner<T> {}
+unsafe impl<T: Sync + Send> Sync for ArcInner<T> {}
+
+impl<T> Arc<T> {
     /// Constructs a new `Arc<T>`.
     ///
     /// # Examples
@@ -587,6 +597,7 @@ mod tests {
     use std::str::Str;
     use std::sync::atomic;
     use std::task;
+    use std::kinds::Send;
     use std::vec::Vec;
     use super::{Arc, Weak, weak_count, strong_count};
     use std::sync::Mutex;
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 5fd234192c5..3c6b2d2cbc0 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -19,6 +19,7 @@ use core::hash::{mod, Hash};
 use core::kinds::Sized;
 use core::mem;
 use core::option::Option;
+use core::ptr::Unique;
 use core::raw::TraitObject;
 use core::result::Result;
 use core::result::Result::{Ok, Err};
@@ -44,7 +45,7 @@ pub static HEAP: () = ();
 /// A type that represents a uniquely-owned value.
 #[lang = "owned_box"]
 #[unstable = "custom allocators will add an additional type parameter (with default)"]
-pub struct Box<T>(*mut T);
+pub struct Box<T>(Unique<T>);
 
 #[stable]
 impl<T: Default> Default for Box<T> {
diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs
index de2a7307440..ee61004d199 100644
--- a/src/libcollections/dlist.rs
+++ b/src/libcollections/dlist.rs
@@ -43,6 +43,8 @@ struct Rawlink<T> {
 }
 
 impl<T> Copy for Rawlink<T> {}
+unsafe impl<T:'static+Send> Send for Rawlink<T> {}
+unsafe impl<T:Send+Sync> Sync for Rawlink<T> {}
 
 struct Node<T> {
     next: Link<T>,
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index fa0e4a2340e..d700b187e8a 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -58,7 +58,7 @@ use core::kinds::marker::{ContravariantLifetime, InvariantType};
 use core::mem;
 use core::num::{Int, UnsignedInt};
 use core::ops;
-use core::ptr;
+use core::ptr::{mod, Unique};
 use core::raw::Slice as RawSlice;
 use core::uint;
 
@@ -133,7 +133,7 @@ use slice::CloneSliceExt;
 #[unsafe_no_drop_flag]
 #[stable]
 pub struct Vec<T> {
-    ptr: *mut T,
+    ptr: Unique<T>,
     len: uint,
     cap: uint,
 }
@@ -176,7 +176,7 @@ impl<T> Vec<T> {
         // non-null value which is fine since we never call deallocate on the ptr
         // if cap is 0. The reason for this is because the pointer of a slice
         // being NULL would break the null pointer optimization for enums.
-        Vec { ptr: EMPTY as *mut T, len: 0, cap: 0 }
+        Vec { ptr: Unique(EMPTY as *mut T), len: 0, cap: 0 }
     }
 
     /// Constructs a new, empty `Vec<T>` with the specified capacity.
@@ -209,7 +209,7 @@ impl<T> Vec<T> {
     #[stable]
     pub fn with_capacity(capacity: uint) -> Vec<T> {
         if mem::size_of::<T>() == 0 {
-            Vec { ptr: EMPTY as *mut T, len: 0, cap: uint::MAX }
+            Vec { ptr: Unique(EMPTY as *mut T), len: 0, cap: uint::MAX }
         } else if capacity == 0 {
             Vec::new()
         } else {
@@ -217,7 +217,7 @@ impl<T> Vec<T> {
                                .expect("capacity overflow");
             let ptr = unsafe { allocate(size, mem::min_align_of::<T>()) };
             if ptr.is_null() { ::alloc::oom() }
-            Vec { ptr: ptr as *mut T, len: 0, cap: capacity }
+            Vec { ptr: Unique(ptr as *mut T), len: 0, cap: capacity }
         }
     }
 
@@ -284,7 +284,7 @@ impl<T> Vec<T> {
     #[unstable = "needs finalization"]
     pub unsafe fn from_raw_parts(ptr: *mut T, length: uint,
                                  capacity: uint) -> Vec<T> {
-        Vec { ptr: ptr, len: length, cap: capacity }
+        Vec { ptr: Unique(ptr), len: length, cap: capacity }
     }
 
     /// Creates a vector by copying the elements from a raw pointer.
@@ -795,7 +795,7 @@ impl<T> Vec<T> {
         if self.len == 0 {
             if self.cap != 0 {
                 unsafe {
-                    dealloc(self.ptr, self.cap)
+                    dealloc(self.ptr.0, self.cap)
                 }
                 self.cap = 0;
             }
@@ -803,11 +803,11 @@ impl<T> Vec<T> {
             unsafe {
                 // Overflow check is unnecessary as the vector is already at
                 // least this large.
-                self.ptr = reallocate(self.ptr as *mut u8,
-                                      self.cap * mem::size_of::<T>(),
-                                      self.len * mem::size_of::<T>(),
-                                      mem::min_align_of::<T>()) as *mut T;
-                if self.ptr.is_null() { ::alloc::oom() }
+                self.ptr = Unique(reallocate(self.ptr.0 as *mut u8,
+                                               self.cap * mem::size_of::<T>(),
+                                               self.len * mem::size_of::<T>(),
+                                               mem::min_align_of::<T>()) as *mut T);
+                if self.ptr.0.is_null() { ::alloc::oom() }
             }
             self.cap = self.len;
         }
@@ -867,7 +867,7 @@ impl<T> Vec<T> {
     pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
         unsafe {
             mem::transmute(RawSlice {
-                data: self.ptr as *const T,
+                data: self.ptr.0 as *const T,
                 len: self.len,
             })
         }
@@ -890,9 +890,9 @@ impl<T> Vec<T> {
     #[unstable = "matches collection reform specification, waiting for dust to settle"]
     pub fn into_iter(self) -> IntoIter<T> {
         unsafe {
-            let ptr = self.ptr;
+            let ptr = self.ptr.0;
             let cap = self.cap;
-            let begin = self.ptr as *const T;
+            let begin = self.ptr.0 as *const T;
             let end = if mem::size_of::<T>() == 0 {
                 (ptr as uint + self.len()) as *const T
             } else {
@@ -1110,14 +1110,14 @@ impl<T> Vec<T> {
             let size = max(old_size, 2 * mem::size_of::<T>()) * 2;
             if old_size > size { panic!("capacity overflow") }
             unsafe {
-                self.ptr = alloc_or_realloc(self.ptr, old_size, size);
-                if self.ptr.is_null() { ::alloc::oom() }
+                self.ptr = Unique(alloc_or_realloc(self.ptr.0, old_size, size));
+                if self.ptr.0.is_null() { ::alloc::oom() }
             }
             self.cap = max(self.cap, 2) * 2;
         }
 
         unsafe {
-            let end = (self.ptr as *const T).offset(self.len as int) as *mut T;
+            let end = self.ptr.0.offset(self.len as int);
             ptr::write(&mut *end, value);
             self.len += 1;
         }
@@ -1162,11 +1162,11 @@ impl<T> Vec<T> {
     #[unstable = "matches collection reform specification, waiting for dust to settle"]
     pub fn drain<'a>(&'a mut self) -> Drain<'a, T> {
         unsafe {
-            let begin = self.ptr as *const T;
+            let begin = self.ptr.0 as *const T;
             let end = if mem::size_of::<T>() == 0 {
-                (self.ptr as uint + self.len()) as *const T
+                (self.ptr.0 as uint + self.len()) as *const T
             } else {
-                self.ptr.offset(self.len() as int) as *const T
+                self.ptr.0.offset(self.len() as int) as *const T
             };
             self.set_len(0);
             Drain {
@@ -1231,8 +1231,10 @@ impl<T> Vec<T> {
             let size = capacity.checked_mul(mem::size_of::<T>())
                                .expect("capacity overflow");
             unsafe {
-                self.ptr = alloc_or_realloc(self.ptr, self.cap * mem::size_of::<T>(), size);
-                if self.ptr.is_null() { ::alloc::oom() }
+                self.ptr = Unique(alloc_or_realloc(self.ptr.0,
+                                                     self.cap * mem::size_of::<T>(),
+                                                     size));
+                if self.ptr.0.is_null() { ::alloc::oom() }
             }
             self.cap = capacity;
         }
@@ -1355,7 +1357,7 @@ impl<T> AsSlice<T> for Vec<T> {
     fn as_slice<'a>(&'a self) -> &'a [T] {
         unsafe {
             mem::transmute(RawSlice {
-                data: self.ptr as *const T,
+                data: self.ptr.0 as *const T,
                 len: self.len
             })
         }
@@ -1380,7 +1382,7 @@ impl<T> Drop for Vec<T> {
                 for x in self.iter() {
                     ptr::read(x);
                 }
-                dealloc(self.ptr, self.cap)
+                dealloc(self.ptr.0, self.cap)
             }
         }
     }
@@ -1418,7 +1420,7 @@ impl<T> IntoIter<T> {
             for _x in self { }
             let IntoIter { allocation, cap, ptr: _ptr, end: _end } = self;
             mem::forget(self);
-            Vec { ptr: allocation, cap: cap, len: 0 }
+            Vec { ptr: Unique(allocation), cap: cap, len: 0 }
         }
     }
 
diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs
index f6bc4dbde38..9452d0a64bf 100644
--- a/src/libcore/atomic.rs
+++ b/src/libcore/atomic.rs
@@ -14,6 +14,8 @@
 
 pub use self::Ordering::*;
 
+use kinds::Sync;
+
 use intrinsics;
 use cell::UnsafeCell;
 
@@ -23,24 +25,32 @@ pub struct AtomicBool {
     v: UnsafeCell<uint>,
 }
 
+unsafe impl Sync for AtomicBool {}
+
 /// A signed integer type which can be safely shared between threads.
 #[stable]
 pub struct AtomicInt {
     v: UnsafeCell<int>,
 }
 
+unsafe impl Sync for AtomicInt {}
+
 /// An unsigned integer type which can be safely shared between threads.
 #[stable]
 pub struct AtomicUint {
     v: UnsafeCell<uint>,
 }
 
+unsafe impl Sync for AtomicUint {}
+
 /// A raw pointer type which can be safely shared between threads.
 #[stable]
 pub struct AtomicPtr<T> {
     p: UnsafeCell<uint>,
 }
 
+unsafe impl<T> Sync for AtomicPtr<T> {}
+
 /// Atomic memory orderings
 ///
 /// Memory orderings limit the ways that both the compiler and CPU may reorder
diff --git a/src/libcore/kinds.rs b/src/libcore/kinds.rs
index b0f46e3d68c..fb030ea45f3 100644
--- a/src/libcore/kinds.rs
+++ b/src/libcore/kinds.rs
@@ -19,7 +19,7 @@
 
 /// Types able to be transferred across task boundaries.
 #[lang="send"]
-pub trait Send for Sized? : 'static {
+pub unsafe trait Send for Sized? : 'static {
     // empty.
 }
 
@@ -81,7 +81,7 @@ pub trait Copy for Sized? {
 /// reference; not doing this is undefined behaviour (for example,
 /// `transmute`-ing from `&T` to `&mut T` is illegal).
 #[lang="sync"]
-pub trait Sync for Sized? {
+pub unsafe trait Sync for Sized? {
     // Empty
 }
 
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index b226d4a6de4..8c9d77a0e9c 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -92,6 +92,7 @@ use clone::Clone;
 use intrinsics;
 use option::Option;
 use option::Option::{Some, None};
+use kinds::{Send, Sync};
 
 use cmp::{PartialEq, Eq, Ord, PartialOrd, Equiv};
 use cmp::Ordering;
@@ -501,3 +502,35 @@ impl<T> PartialOrd for *mut T {
     #[inline]
     fn ge(&self, other: &*mut T) -> bool { *self >= *other }
 }
+
+/// A wrapper around a raw `*mut T` that indicates that the possessor
+/// of this wrapper owns the referent. This in turn implies that the
+/// `Unique<T>` is `Send`/`Sync` if `T` is `Send`/`Sync`, unlike a
+/// raw `*mut T` (which conveys no particular ownership semantics).
+/// Useful for building abstractions like `Vec<T>` or `Box<T>`, which
+/// internally use raw pointers to manage the memory that they own.
+pub struct Unique<T>(pub *mut T);
+
+/// `Unique` pointers are `Send` if `T` is `Send` because the data they
+/// reference is unaliased. Note that this aliasing invariant is
+/// unenforced by the type system; the abstraction using the
+/// `Unique` must enforce it.
+unsafe impl<T:Send> Send for Unique<T> { }
+
+/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they
+/// reference is unaliased. Note that this aliasing invariant is
+/// unenforced by the type system; the abstraction using the
+/// `Unique` must enforce it.
+unsafe impl<T:Sync> Sync for Unique<T> { }
+
+impl<T> Unique<T> {
+    /// Returns a null Unique.
+    pub fn null() -> Unique<T> {
+        Unique(RawPtr::null())
+    }
+
+    /// Return an (unsafe) pointer into the memory owned by `self`.
+    pub unsafe fn offset(self, offset: int) -> *mut T {
+        (self.0 as *const T).offset(offset) as *mut T
+    }
+}
diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs
index 2c8e5638e49..8c4f74027a5 100644
--- a/src/libflate/lib.rs
+++ b/src/libflate/lib.rs
@@ -27,8 +27,9 @@
 
 extern crate libc;
 
-use std::c_vec::CVec;
 use libc::{c_void, size_t, c_int};
+use std::c_vec::CVec;
+use std::ptr::Unique;
 
 #[link(name = "miniz", kind = "static")]
 extern {
@@ -59,7 +60,8 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option<CVec<u8>> {
                                              &mut outsz,
                                              flags);
         if !res.is_null() {
-            Some(CVec::new_with_dtor(res as *mut u8, outsz as uint, move|:| libc::free(res)))
+            let res = Unique(res);
+            Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0)))
         } else {
             None
         }
@@ -84,7 +86,8 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option<CVec<u8>> {
                                                &mut outsz,
                                                flags);
         if !res.is_null() {
-            Some(CVec::new_with_dtor(res as *mut u8, outsz as uint, move|:| libc::free(res)))
+            let res = Unique(res);
+            Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0)))
         } else {
             None
         }
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 4c3cb99f64d..1ea79bdf606 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -67,5 +67,6 @@ register_diagnostics! {
     E0173,
     E0174,
     E0177,
-    E0178
+    E0178,
+    E0179
 }
diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs
index 6ff34d62500..14f927f5b1e 100644
--- a/src/librustc/middle/check_static.rs
+++ b/src/librustc/middle/check_static.rs
@@ -31,6 +31,7 @@ use middle::infer;
 use middle::traits;
 use middle::mem_categorization as mc;
 use middle::expr_use_visitor as euv;
+use util::common::ErrorReported;
 use util::nodemap::NodeSet;
 
 use syntax::ast;
@@ -119,12 +120,19 @@ impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> {
         let ty = ty::node_id_to_type(self.tcx, e.id);
         let infcx = infer::new_infer_ctxt(self.tcx);
         let mut fulfill_cx = traits::FulfillmentContext::new();
-        fulfill_cx.register_builtin_bound(self.tcx, ty, ty::BoundSync,
-                                          traits::ObligationCause::dummy());
-        let env = ty::empty_parameter_environment();
-        if !fulfill_cx.select_all_or_error(&infcx, &env, self.tcx).is_ok() {
-            self.tcx.sess.span_err(e.span, "shared static items must have a \
-                                            type which implements Sync");
+        match traits::poly_trait_ref_for_builtin_bound(self.tcx, ty::BoundSync, ty) {
+            Ok(trait_ref) => {
+                let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
+                fulfill_cx.register_trait_ref(self.tcx, trait_ref, cause);
+                let env = ty::empty_parameter_environment();
+                match fulfill_cx.select_all_or_error(&infcx, &env, self.tcx) {
+                    Ok(()) => { },
+                    Err(ref errors) => {
+                      traits::report_fulfillment_errors(&infcx, errors);
+                    }
+                }
+            }
+            Err(ErrorReported) => { }
         }
     }
 }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 9f7472c2c73..87b378d579c 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -113,7 +113,7 @@ pub struct Upvar {
 // different kinds of pointers:
 #[deriving(Clone, Copy, PartialEq, Eq, Hash, Show)]
 pub enum PointerKind {
-    OwnedPtr,
+    Unique,
     BorrowedPtr(ty::BorrowKind, ty::Region),
     Implicit(ty::BorrowKind, ty::Region),     // Implicit deref of a borrowed ptr.
     UnsafePtr(ast::Mutability)
@@ -199,7 +199,7 @@ pub fn opt_deref_kind(t: Ty) -> Option<deref_kind> {
     match t.sty {
         ty::ty_uniq(_) |
         ty::ty_closure(box ty::ClosureTy {store: ty::UniqTraitStore, ..}) => {
-            Some(deref_ptr(OwnedPtr))
+            Some(deref_ptr(Unique))
         }
 
         ty::ty_rptr(r, mt) => {
@@ -316,7 +316,7 @@ impl MutabilityCategory {
     pub fn from_pointer_kind(base_mutbl: MutabilityCategory,
                              ptr: PointerKind) -> MutabilityCategory {
         match ptr {
-            OwnedPtr => {
+            Unique => {
                 base_mutbl.inherit()
             }
             BorrowedPtr(borrow_kind, _) | Implicit(borrow_kind, _) => {
@@ -1339,7 +1339,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                           Implicit(..) => {
                             "dereference (dereference is implicit, due to indexing)".to_string()
                           }
-                          OwnedPtr => format!("dereference of `{}`", ptr_sigil(pk)),
+                          Unique => format!("dereference of `{}`", ptr_sigil(pk)),
                           _ => format!("dereference of `{}`-pointer", ptr_sigil(pk))
                       }
                   }
@@ -1400,7 +1400,7 @@ impl<'tcx> cmt_<'tcx> {
             }
             cat_downcast(ref b, _) |
             cat_interior(ref b, _) |
-            cat_deref(ref b, _, OwnedPtr) => {
+            cat_deref(ref b, _, Unique) => {
                 b.guarantor()
             }
         }
@@ -1419,7 +1419,7 @@ impl<'tcx> cmt_<'tcx> {
             cat_deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
             cat_deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
             cat_downcast(ref b, _) |
-            cat_deref(ref b, _, OwnedPtr) |
+            cat_deref(ref b, _, Unique) |
             cat_interior(ref b, _) => {
                 // Aliasability depends on base cmt
                 b.freely_aliasable(ctxt)
@@ -1511,7 +1511,7 @@ impl<'tcx> Repr<'tcx> for categorization<'tcx> {
 
 pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
     match ptr {
-        OwnedPtr => "Box",
+        Unique => "Box",
         BorrowedPtr(ty::ImmBorrow, _) |
         Implicit(ty::ImmBorrow, _) => "&",
         BorrowedPtr(ty::MutBorrow, _) |
diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs
new file mode 100644
index 00000000000..462857de1d4
--- /dev/null
+++ b/src/librustc/middle/traits/error_reporting.rs
@@ -0,0 +1,349 @@
+// Copyright 2014 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.
+
+use super::{FulfillmentError, FulfillmentErrorCode,
+            ObligationCauseCode, SelectionError,
+            PredicateObligation, OutputTypeParameterMismatch};
+
+use middle::infer::InferCtxt;
+use middle::ty::{mod};
+use syntax::codemap::Span;
+use util::ppaux::{Repr, UserString};
+
+pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+                                           errors: &Vec<FulfillmentError<'tcx>>) {
+    for error in errors.iter() {
+        report_fulfillment_error(infcx, error);
+    }
+}
+
+fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+                                      error: &FulfillmentError<'tcx>) {
+    match error.code {
+        FulfillmentErrorCode::CodeSelectionError(ref e) => {
+            report_selection_error(infcx, &error.obligation, e);
+        }
+        FulfillmentErrorCode::CodeAmbiguity => {
+            maybe_report_ambiguity(infcx, &error.obligation);
+        }
+    }
+}
+
+pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+                                        obligation: &PredicateObligation<'tcx>,
+                                        error: &SelectionError<'tcx>)
+{
+    match *error {
+        SelectionError::Overflow => {
+            // We could track the stack here more precisely if we wanted, I imagine.
+            match obligation.trait_ref {
+                ty::Predicate::Trait(ref trait_ref) => {
+                    let trait_ref =
+                        infcx.resolve_type_vars_if_possible(&**trait_ref);
+                    infcx.tcx.sess.span_err(
+                        obligation.cause.span,
+                        format!(
+                            "overflow evaluating the trait `{}` for the type `{}`",
+                            trait_ref.user_string(infcx.tcx),
+                            trait_ref.self_ty().user_string(infcx.tcx))[]);
+                }
+
+                ty::Predicate::Equate(ref predicate) => {
+                    let predicate = infcx.resolve_type_vars_if_possible(predicate);
+                    let err = infcx.equality_predicate(obligation.cause.span,
+                                                       &predicate).unwrap_err();
+
+                    infcx.tcx.sess.span_err(
+                        obligation.cause.span,
+                        format!(
+                            "the requirement `{}` is not satisfied (`{}`)",
+                            predicate.user_string(infcx.tcx),
+                            ty::type_err_to_str(infcx.tcx, &err)).as_slice());
+                }
+
+                ty::Predicate::TypeOutlives(..) |
+                ty::Predicate::RegionOutlives(..) => {
+                    infcx.tcx.sess.span_err(
+                        obligation.cause.span,
+                        format!("overflow evaluating lifetime predicate").as_slice());
+                }
+            }
+
+            let current_limit = infcx.tcx.sess.recursion_limit.get();
+            let suggested_limit = current_limit * 2;
+            infcx.tcx.sess.span_note(
+                obligation.cause.span,
+                format!(
+                    "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
+                    suggested_limit)[]);
+
+            note_obligation_cause(infcx, obligation);
+        }
+        SelectionError::Unimplemented => {
+            match obligation.trait_ref {
+                ty::Predicate::Trait(ref trait_ref) => {
+                    let trait_ref =
+                        infcx.resolve_type_vars_if_possible(
+                            &**trait_ref);
+                    if !ty::type_is_error(trait_ref.self_ty()) {
+                        infcx.tcx.sess.span_err(
+                            obligation.cause.span,
+                            format!(
+                                "the trait `{}` is not implemented for the type `{}`",
+                                trait_ref.user_string(infcx.tcx),
+                                trait_ref.self_ty().user_string(infcx.tcx)).as_slice());
+                        note_obligation_cause(infcx, obligation);
+                    }
+                }
+
+                ty::Predicate::Equate(ref predicate) => {
+                    let predicate = infcx.resolve_type_vars_if_possible(predicate);
+                    let err = infcx.equality_predicate(obligation.cause.span,
+                                                       &predicate).unwrap_err();
+
+                    infcx.tcx.sess.span_err(
+                        obligation.cause.span,
+                        format!(
+                            "the requirement `{}` is not satisfied (`{}`)",
+                            predicate.user_string(infcx.tcx),
+                            ty::type_err_to_str(infcx.tcx, &err)).as_slice());
+                }
+
+                ty::Predicate::TypeOutlives(..) |
+                ty::Predicate::RegionOutlives(..) => {
+                    let predicate = infcx.resolve_type_vars_if_possible(&obligation.trait_ref);
+                    infcx.tcx.sess.span_err(
+                        obligation.cause.span,
+                        format!(
+                            "the requirement `{}` is not satisfied",
+                            predicate.user_string(infcx.tcx)).as_slice());
+                }
+            }
+        }
+        OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
+            let expected_trait_ref =
+                infcx.resolve_type_vars_if_possible(
+                    &**expected_trait_ref);
+            let actual_trait_ref =
+                infcx.resolve_type_vars_if_possible(
+                    &**actual_trait_ref);
+            if !ty::type_is_error(actual_trait_ref.self_ty()) {
+                infcx.tcx.sess.span_err(
+                    obligation.cause.span,
+                    format!(
+                        "type mismatch: the type `{}` implements the trait `{}`, \
+                         but the trait `{}` is required ({})",
+                        expected_trait_ref.self_ty().user_string(infcx.tcx),
+                        expected_trait_ref.user_string(infcx.tcx),
+                        actual_trait_ref.user_string(infcx.tcx),
+                        ty::type_err_to_str(infcx.tcx, e)).as_slice());
+                note_obligation_cause(infcx, obligation);
+            }
+        }
+    }
+}
+
+fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+                                    obligation: &PredicateObligation<'tcx>) {
+    // Unable to successfully determine, probably means
+    // insufficient type information, but could mean
+    // ambiguous impls. The latter *ought* to be a
+    // coherence violation, so we don't report it here.
+
+    let trait_ref = match obligation.trait_ref {
+        ty::Predicate::Trait(ref trait_ref) => {
+            infcx.resolve_type_vars_if_possible(&**trait_ref)
+        }
+        _ => {
+            infcx.tcx.sess.span_bug(
+                obligation.cause.span,
+                format!("ambiguity from something other than a trait: {}",
+                        obligation.trait_ref.repr(infcx.tcx)).as_slice());
+        }
+    };
+    let self_ty = trait_ref.self_ty();
+
+    debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})",
+           trait_ref.repr(infcx.tcx),
+           self_ty.repr(infcx.tcx),
+           obligation.repr(infcx.tcx));
+    let all_types = &trait_ref.substs().types;
+    if all_types.iter().any(|&t| ty::type_is_error(t)) {
+    } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) {
+        // This is kind of a hack: it frequently happens that some earlier
+        // error prevents types from being fully inferred, and then we get
+        // a bunch of uninteresting errors saying something like "<generic
+        // #0> doesn't implement Sized".  It may even be true that we
+        // could just skip over all checks where the self-ty is an
+        // inference variable, but I was afraid that there might be an
+        // inference variable created, registered as an obligation, and
+        // then never forced by writeback, and hence by skipping here we'd
+        // be ignoring the fact that we don't KNOW the type works
+        // out. Though even that would probably be harmless, given that
+        // we're only talking about builtin traits, which are known to be
+        // inhabited. But in any case I just threw in this check for
+        // has_errors() to be sure that compilation isn't happening
+        // anyway. In that case, why inundate the user.
+        if !infcx.tcx.sess.has_errors() {
+            if infcx.tcx.lang_items.sized_trait()
+                  .map_or(false, |sized_id| sized_id == trait_ref.def_id()) {
+                infcx.tcx.sess.span_err(
+                    obligation.cause.span,
+                    format!(
+                        "unable to infer enough type information about `{}`; type annotations \
+                         required",
+                        self_ty.user_string(infcx.tcx)).as_slice());
+            } else {
+                infcx.tcx.sess.span_err(
+                    obligation.cause.span,
+                    format!(
+                        "unable to infer enough type information to \
+                         locate the impl of the trait `{}` for \
+                         the type `{}`; type annotations required",
+                        trait_ref.user_string(infcx.tcx),
+                        self_ty.user_string(infcx.tcx))[]);
+                note_obligation_cause(infcx, obligation);
+            }
+        }
+    } else if !infcx.tcx.sess.has_errors() {
+         // Ambiguity. Coherence should have reported an error.
+        infcx.tcx.sess.span_bug(
+            obligation.cause.span,
+            format!(
+                "coherence failed to report ambiguity: \
+                 cannot locate the impl of the trait `{}` for \
+                 the type `{}`",
+                trait_ref.user_string(infcx.tcx),
+                self_ty.user_string(infcx.tcx))[]);
+    }
+}
+
+fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+                                   obligation: &PredicateObligation<'tcx>)
+{
+    let trait_ref = match obligation.trait_ref {
+        ty::Predicate::Trait(ref trait_ref) => {
+            infcx.resolve_type_vars_if_possible(&**trait_ref)
+        }
+        _ => {
+            infcx.tcx.sess.span_bug(
+                obligation.cause.span,
+                format!("ambiguity from something other than a trait: {}",
+                        obligation.trait_ref.repr(infcx.tcx)).as_slice());
+        }
+    };
+
+    note_obligation_cause_code(infcx,
+                               &trait_ref,
+                               obligation.cause.span,
+                               &obligation.cause.code)
+}
+
+fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+                                        trait_ref: &ty::PolyTraitRef<'tcx>,
+                                        cause_span: Span,
+                                        cause_code: &ObligationCauseCode<'tcx>)
+{
+    let tcx = infcx.tcx;
+    let trait_name = ty::item_path_str(tcx, trait_ref.def_id());
+    match *cause_code {
+        ObligationCauseCode::MiscObligation => { }
+        ObligationCauseCode::ItemObligation(item_def_id) => {
+            let item_name = ty::item_path_str(tcx, item_def_id);
+            tcx.sess.span_note(
+                cause_span,
+                format!(
+                    "the trait `{}` must be implemented because it is required by `{}`",
+                    trait_name,
+                    item_name).as_slice());
+        }
+        ObligationCauseCode::ObjectCastObligation(object_ty) => {
+            tcx.sess.span_note(
+                cause_span,
+                format!(
+                    "the trait `{}` must be implemented for the cast \
+                     to the object type `{}`",
+                    trait_name,
+                    infcx.ty_to_string(object_ty)).as_slice());
+        }
+        ObligationCauseCode::RepeatVec => {
+            tcx.sess.span_note(
+                cause_span,
+                "the `Copy` trait is required because the \
+                 repeated element will be copied");
+        }
+        ObligationCauseCode::VariableType(_) => {
+            tcx.sess.span_note(
+                cause_span,
+                "all local variables must have a statically known size");
+        }
+        ObligationCauseCode::ReturnType => {
+            tcx.sess.span_note(
+                cause_span,
+                "the return type of a function must have a \
+                 statically known size");
+        }
+        ObligationCauseCode::AssignmentLhsSized => {
+            tcx.sess.span_note(
+                cause_span,
+                "the left-hand-side of an assignment must have a statically known size");
+        }
+        ObligationCauseCode::StructInitializerSized => {
+            tcx.sess.span_note(
+                cause_span,
+                "structs must have a statically known size to be initialized");
+        }
+        ObligationCauseCode::ClosureCapture(var_id, closure_span, builtin_bound) => {
+            let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap();
+            let trait_name = ty::item_path_str(tcx, def_id);
+            let name = ty::local_var_name_str(tcx, var_id);
+            span_note!(tcx.sess, closure_span,
+                       "the closure that captures `{}` requires that all captured variables \
+                       implement the trait `{}`",
+                       name,
+                       trait_name);
+        }
+        ObligationCauseCode::FieldSized => {
+            span_note!(tcx.sess, cause_span,
+                       "only the last field of a struct or enum variant \
+                       may have a dynamically sized type")
+        }
+        ObligationCauseCode::ObjectSized => {
+            span_note!(tcx.sess, cause_span,
+                       "only sized types can be made into objects");
+        }
+        ObligationCauseCode::SharedStatic => {
+            span_note!(tcx.sess, cause_span,
+                       "shared static variables must have a type that implements `Sync`");
+        }
+        ObligationCauseCode::BuiltinDerivedObligation(ref root_trait_ref, ref root_cause_code) => {
+            let root_trait_ref =
+                infcx.resolve_type_vars_if_possible(&**root_trait_ref);
+            span_note!(tcx.sess, cause_span,
+                       "the type `{}` must implement `{}` because it appears within the type `{}`",
+                       trait_ref.self_ty().user_string(infcx.tcx),
+                       trait_ref.user_string(infcx.tcx),
+                       root_trait_ref.self_ty().user_string(infcx.tcx));
+            note_obligation_cause_code(infcx, &root_trait_ref, cause_span, &**root_cause_code);
+        }
+        ObligationCauseCode::ImplDerivedObligation(ref root_trait_ref, ref root_cause_code) => {
+            let root_trait_ref =
+                infcx.resolve_type_vars_if_possible(&**root_trait_ref);
+            span_note!(tcx.sess, cause_span,
+                       "the type `{}` must implement `{}` due to the requirements \
+                        on the impl of `{}` for the type `{}`",
+                       trait_ref.self_ty().user_string(infcx.tcx),
+                       trait_ref.user_string(infcx.tcx),
+                       root_trait_ref.user_string(infcx.tcx),
+                       root_trait_ref.self_ty().user_string(infcx.tcx));
+            note_obligation_cause_code(infcx, &root_trait_ref, cause_span, &**root_cause_code);
+        }
+    }
+}
diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs
index 72e4eb5d1d6..e9e80ed8c18 100644
--- a/src/librustc/middle/traits/fulfill.rs
+++ b/src/librustc/middle/traits/fulfill.rs
@@ -305,7 +305,7 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
     let tcx = selcx.tcx();
     match predicate.trait_ref {
         ty::Predicate::Trait(ref trait_ref) => {
-            let trait_obligation = Obligation { cause: predicate.cause,
+            let trait_obligation = Obligation { cause: predicate.cause.clone(),
                                                 recursion_depth: predicate.recursion_depth,
                                                 trait_ref: trait_ref.clone() };
             match selcx.select(&trait_obligation) {
@@ -368,7 +368,9 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
                         CodeSelectionError(Unimplemented)));
             } else {
                 let ty::OutlivesPredicate(t_a, r_b) = binder.0;
-                register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations);
+                register_region_obligation(tcx, t_a, r_b,
+                                           predicate.cause.clone(),
+                                           region_obligations);
             }
             true
         }
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index 8028971a463..6597730846d 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -23,6 +23,7 @@ use std::slice::Iter;
 use syntax::ast;
 use syntax::codemap::{Span, DUMMY_SP};
 
+pub use self::error_reporting::report_fulfillment_errors;
 pub use self::fulfill::{FulfillmentContext, RegionObligation};
 pub use self::select::SelectionContext;
 pub use self::select::SelectionCache;
@@ -36,6 +37,7 @@ pub use self::util::transitive_bounds;
 pub use self::util::poly_trait_ref_for_builtin_bound;
 
 mod coherence;
+mod error_reporting;
 mod fulfill;
 mod select;
 mod util;
@@ -57,7 +59,7 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
 pub type TraitObligation<'tcx> = Obligation<'tcx, Rc<ty::PolyTraitRef<'tcx>>>;
 
 /// Why did we incur this obligation? Used for error reporting.
-#[deriving(Copy, Clone)]
+#[deriving(Clone)]
 pub struct ObligationCause<'tcx> {
     pub span: Span,
 
@@ -72,7 +74,7 @@ pub struct ObligationCause<'tcx> {
     pub code: ObligationCauseCode<'tcx>
 }
 
-#[deriving(Copy, Clone)]
+#[deriving(Clone)]
 pub enum ObligationCauseCode<'tcx> {
     /// Not well classified or should be obvious from span.
     MiscObligation,
@@ -84,9 +86,6 @@ pub enum ObligationCauseCode<'tcx> {
     /// Obligation incurred due to an object cast.
     ObjectCastObligation(/* Object type */ Ty<'tcx>),
 
-    /// To implement drop, type must be sendable.
-    DropTrait,
-
     /// Various cases where expressions must be sized/copy/etc:
     AssignmentLhsSized,        // L = X implies that L is Sized
     StructInitializerSized,    // S { ... } must be Sized
@@ -103,6 +102,13 @@ pub enum ObligationCauseCode<'tcx> {
 
     // Only Sized types can be made into objects
     ObjectSized,
+
+    // static items must have `Sync` type
+    SharedStatic,
+
+    BuiltinDerivedObligation(Rc<ty::PolyTraitRef<'tcx>>, Rc<ObligationCauseCode<'tcx>>),
+
+    ImplDerivedObligation(Rc<ty::PolyTraitRef<'tcx>>, Rc<ObligationCauseCode<'tcx>>),
 }
 
 pub type Obligations<'tcx, O> = subst::VecPerParamSpace<Obligation<'tcx, O>>;
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 5ee6dec7830..42b753927d5 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -18,6 +18,7 @@ use self::BuiltinBoundConditions::*;
 use self::EvaluationResult::*;
 
 use super::{PredicateObligation, Obligation, TraitObligation, ObligationCause};
+use super::{ObligationCauseCode, BuiltinDerivedObligation};
 use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
 use super::{Selection};
 use super::{SelectionResult};
@@ -256,7 +257,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let obligation =
             util::predicate_for_builtin_bound(
                 self.tcx(),
-                previous_stack.obligation.cause,
+                previous_stack.obligation.cause.clone(),
                 bound,
                 previous_stack.obligation.recursion_depth + 1,
                 ty);
@@ -416,7 +417,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Ok(substs) => {
                     let vtable_impl = self.vtable_impl(impl_def_id,
                                                        substs,
-                                                       obligation.cause,
+                                                       obligation.cause.clone(),
                                                        obligation.recursion_depth + 1,
                                                        skol_map,
                                                        snapshot);
@@ -663,13 +664,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // behavior, ignore user-defined impls here. This will
                 // go away by the time 1.0 is released.
                 if !self.tcx().sess.features.borrow().opt_out_copy {
-                    try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
+                    try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec));
                 }
 
                 try!(self.assemble_builtin_bound_candidates(ty::BoundCopy,
                                                             stack,
                                                             &mut candidates));
             }
+            Some(bound @ ty::BoundSend) |
+            Some(bound @ ty::BoundSync) => {
+                try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec));
+
+                // No explicit impls were declared for this type, consider the fallback rules.
+                if candidates.vec.is_empty() {
+                    try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates));
+                }
+            }
+
+            Some(bound @ ty::BoundSized) => {
+                // Sized and Copy are always automatically computed.
+                try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates));
+            }
 
             None => {
                 // For the time being, we ignore user-defined impls for builtin-bounds, other than
@@ -677,11 +692,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // (And unboxed candidates only apply to the Fn/FnMut/etc traits.)
                 try!(self.assemble_unboxed_closure_candidates(obligation, &mut candidates));
                 try!(self.assemble_fn_pointer_candidates(obligation, &mut candidates));
-                try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
-            }
-
-            Some(bound) => {
-                try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates));
+                try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec));
             }
         }
 
@@ -816,7 +827,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// Search for impls that might apply to `obligation`.
     fn assemble_candidates_from_impls(&mut self,
                                       obligation: &TraitObligation<'tcx>,
-                                      candidates: &mut CandidateSet<'tcx>)
+                                      candidate_vec: &mut Vec<Candidate<'tcx>>)
                                       -> Result<(), SelectionError<'tcx>>
     {
         let all_impls = self.all_impls(obligation.trait_ref.def_id());
@@ -827,7 +838,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 match self.match_impl(impl_def_id, obligation, snapshot,
                                       &skol_map, Rc::new(skol_obligation_trait_ref)) {
                     Ok(_) => {
-                        candidates.vec.push(ImplCandidate(impl_def_id));
+                        candidate_vec.push(ImplCandidate(impl_def_id));
                     }
                     Err(()) => { }
                 }
@@ -1007,7 +1018,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
             }
 
-            ty::ty_ptr(ty::mt { ty: referent_ty, .. }) => {     // *const T, *mut T
+            ty::ty_ptr(..) => {     // *const T, *mut T
                 match bound {
                     ty::BoundCopy |
                     ty::BoundSized => {
@@ -1016,7 +1027,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                     ty::BoundSync |
                     ty::BoundSend => {
-                        Ok(If(vec![referent_ty]))
+                        // sync and send are not implemented for *const, *mut
+                        Err(Unimplemented)
                     }
                 }
             }
@@ -1323,16 +1335,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ty::BoundSync => {
                     if
                         Some(def_id) == tcx.lang_items.no_sync_bound() ||
-                        Some(def_id) == tcx.lang_items.managed_bound()
-                    {
-                        return Err(Unimplemented)
-                    } else if
+                        Some(def_id) == tcx.lang_items.managed_bound() ||
                         Some(def_id) == tcx.lang_items.unsafe_type()
                     {
-                        // FIXME(#13231) -- we currently consider `UnsafeCell<T>`
-                        // to always be sync. This is allow for types like `Queue`
-                        // and `Mutex`, where `Queue<T> : Sync` is `T : Send`.
-                        return Ok(If(Vec::new()));
+                        return Err(Unimplemented)
                     }
                 }
 
@@ -1407,7 +1413,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // where-clause trait-ref could be unified with the obligation
         // trait-ref. Repeat that unification now without any
         // transactional boundary; it should not fail.
-        match self.confirm_poly_trait_refs(obligation.cause,
+        match self.confirm_poly_trait_refs(obligation.cause.clone(),
                                            obligation.trait_ref.clone(),
                                            param.bound.clone()) {
             Ok(()) => Ok(param),
@@ -1446,10 +1452,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                            nested: Vec<Ty<'tcx>>)
                            -> VtableBuiltinData<PredicateObligation<'tcx>>
     {
+        let derived_cause = self.derived_cause(obligation, BuiltinDerivedObligation);
         let obligations = nested.iter().map(|&t| {
             util::predicate_for_builtin_bound(
                 self.tcx(),
-                obligation.cause,
+                derived_cause.clone(),
                 bound,
                 obligation.recursion_depth + 1,
                 t)
@@ -1462,7 +1469,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // as a special case, `Send` requires `'static`
         if bound == ty::BoundSend {
             obligations.push(Obligation {
-                cause: obligation.cause,
+                cause: obligation.cause.clone(),
                 recursion_depth: obligation.recursion_depth+1,
                 trait_ref: ty::Binder(ty::OutlivesPredicate(obligation.self_ty(),
                                                             ty::ReStatic)).as_predicate(),
@@ -1496,7 +1503,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             let substs = self.rematch_impl(impl_def_id, obligation,
                                            snapshot, &skol_map, Rc::new(skol_obligation_trait_ref));
             debug!("confirm_impl_candidate substs={}", substs);
-            Ok(self.vtable_impl(impl_def_id, substs, obligation.cause,
+            Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(),
                                 obligation.recursion_depth + 1, skol_map, snapshot))
         })
     }
@@ -1570,10 +1577,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             substs: substs,
         }));
 
-        try!(self.confirm_poly_trait_refs(obligation.cause,
+        try!(self.confirm_poly_trait_refs(obligation.cause.clone(),
                                           obligation.trait_ref.clone(),
                                           trait_ref));
-
         Ok(self_ty)
     }
 
@@ -1616,7 +1622,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                closure_def_id.repr(self.tcx()),
                trait_ref.repr(self.tcx()));
 
-        self.confirm_poly_trait_refs(obligation.cause,
+        self.confirm_poly_trait_refs(obligation.cause.clone(),
                                      obligation.trait_ref.clone(),
                                      trait_ref)
     }
@@ -1808,7 +1814,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// back `Ok(T=int)`.
     fn match_inherent_impl(&mut self,
                            impl_def_id: ast::DefId,
-                           obligation_cause: ObligationCause,
+                           obligation_cause: &ObligationCause,
                            obligation_self_ty: Ty<'tcx>)
                            -> Result<Substs<'tcx>,()>
     {
@@ -1841,7 +1847,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     fn match_self_types(&mut self,
-                        cause: ObligationCause,
+                        cause: &ObligationCause,
 
                         // The self type provided by the impl/caller-obligation:
                         provided_self_ty: Ty<'tcx>,
@@ -1920,6 +1926,37 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             None
         }
     }
+
+    #[allow(unused_comparisons)]
+    fn derived_cause(&self,
+                     obligation: &TraitObligation<'tcx>,
+                     variant: fn(Rc<ty::Binder<ty::TraitRef<'tcx>>>,
+                                 Rc<ObligationCauseCode<'tcx>>)
+                                 -> ObligationCauseCode<'tcx>)
+                     -> ObligationCause<'tcx>
+    {
+        /*!
+         * Creates a cause for obligations that are derived from
+         * `obligation` by a recursive search (e.g., for a builtin
+         * bound, or eventually a `impl Foo for ..`). If `obligation`
+         * is itself a derived obligation, this is just a clone, but
+         * otherwise we create a "derived obligation" cause so as to
+         * keep track of the original root obligation for error
+         * reporting.
+         */
+
+        // NOTE(flaper87): As of now, it keeps track of the whole error
+        // chain. Ideally, we should have a way to configure this either
+        // by using -Z verbose or just a CLI argument.
+        if obligation.recursion_depth >= 0 {
+            ObligationCause::new(obligation.cause.span,
+                                 obligation.trait_ref.def_id().node,
+                                 variant(obligation.trait_ref.clone(),
+                                         Rc::new(obligation.cause.code.clone())))
+        } else {
+            obligation.cause.clone()
+        }
+    }
 }
 
 impl<'tcx> Repr<'tcx> for Candidate<'tcx> {
diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs
index 27824ba5c6e..0864b21870d 100644
--- a/src/librustc/middle/traits/util.rs
+++ b/src/librustc/middle/traits/util.rs
@@ -260,7 +260,7 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
            generic_bounds.repr(tcx));
 
     generic_bounds.predicates.map(|predicate| {
-        Obligation { cause: cause,
+        Obligation { cause: cause.clone(),
                      recursion_depth: recursion_depth,
                      trait_ref: predicate.clone() }
     })
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index a35ea30b217..b7cde762a84 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -439,7 +439,7 @@ impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O>
 {
     fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Obligation<'tcx, O> {
         traits::Obligation {
-            cause: self.cause,
+            cause: self.cause.clone(),
             recursion_depth: self.recursion_depth,
             trait_ref: self.trait_ref.fold_with(folder),
         }
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 046b9547cbb..fdb13ecabde 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -31,11 +31,11 @@ use std::rc::Rc;
 
 // FIXME (#16118): These functions are intended to allow the borrow checker to
 // be less precise in its handling of Box while still allowing moves out of a
-// Box. They should be removed when OwnedPtr is removed from LoanPath.
+// Box. They should be removed when Unique is removed from LoanPath.
 
 fn owned_ptr_base_path<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> &'a LoanPath<'tcx> {
-    //! Returns the base of the leftmost dereference of an OwnedPtr in
-    //! `loan_path`. If there is no dereference of an OwnedPtr in `loan_path`,
+    //! Returns the base of the leftmost dereference of an Unique in
+    //! `loan_path`. If there is no dereference of an Unique in `loan_path`,
     //! then it just returns `loan_path` itself.
 
     return match helper(loan_path) {
@@ -46,7 +46,7 @@ fn owned_ptr_base_path<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> &'a LoanPath<
     fn helper<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> Option<&'a LoanPath<'tcx>> {
         match loan_path.kind {
             LpVar(_) | LpUpvar(_) => None,
-            LpExtend(ref lp_base, _, LpDeref(mc::OwnedPtr)) => {
+            LpExtend(ref lp_base, _, LpDeref(mc::Unique)) => {
                 match helper(&**lp_base) {
                     v @ Some(_) => v,
                     None => Some(&**lp_base)
@@ -70,7 +70,7 @@ fn owned_ptr_base_path_rc<'tcx>(loan_path: &Rc<LoanPath<'tcx>>) -> Rc<LoanPath<'
     fn helper<'tcx>(loan_path: &Rc<LoanPath<'tcx>>) -> Option<Rc<LoanPath<'tcx>>> {
         match loan_path.kind {
             LpVar(_) | LpUpvar(_) => None,
-            LpExtend(ref lp_base, _, LpDeref(mc::OwnedPtr)) => {
+            LpExtend(ref lp_base, _, LpDeref(mc::Unique)) => {
                 match helper(lp_base) {
                     v @ Some(_) => v,
                     None => Some(lp_base.clone())
@@ -878,7 +878,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                         }
                     }
 
-                    mc::cat_deref(b, _, mc::OwnedPtr) => {
+                    mc::cat_deref(b, _, mc::Unique) => {
                         assert_eq!(cmt.mutbl, mc::McInherited);
                         cmt = b;
                     }
diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs
index dbbc52cf362..ef9130bb607 100644
--- a/src/librustc_borrowck/borrowck/fragments.rs
+++ b/src/librustc_borrowck/borrowck/fragments.rs
@@ -291,9 +291,9 @@ fn add_fragment_siblings<'tcx>(this: &MoveData<'tcx>,
             add_fragment_siblings(this, tcx, gathered_fragments, loan_parent.clone(), origin_id);
         }
 
-        // *LV for OwnedPtr consumes the contents of the box (at
+        // *LV for Unique consumes the contents of the box (at
         // least when it is non-copy...), so propagate inward.
-        LpExtend(ref loan_parent, _, LpDeref(mc::OwnedPtr)) => {
+        LpExtend(ref loan_parent, _, LpDeref(mc::Unique)) => {
             add_fragment_siblings(this, tcx, gathered_fragments, loan_parent.clone(), origin_id);
         }
 
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index 85cc691fb9d..6f02f447a15 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -189,7 +189,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
             }
         }
 
-        mc::cat_deref(ref b, _, mc::OwnedPtr) => {
+        mc::cat_deref(ref b, _, mc::Unique) => {
             check_and_get_illegal_move_origin(bccx, b)
         }
     }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
index d7c96346463..1c57097ae26 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
@@ -84,7 +84,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
             }
 
             mc::cat_downcast(ref base, _) |
-            mc::cat_deref(ref base, _, mc::OwnedPtr) |     // L-Deref-Send
+            mc::cat_deref(ref base, _, mc::Unique) |     // L-Deref-Send
             mc::cat_interior(ref base, _) => {             // L-Field
                 self.check(base, discr_scope)
             }
@@ -129,7 +129,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
                 r
             }
             mc::cat_downcast(ref cmt, _) |
-            mc::cat_deref(ref cmt, _, mc::OwnedPtr) |
+            mc::cat_deref(ref cmt, _, mc::Unique) |
             mc::cat_interior(ref cmt, _) => {
                 self.scope(cmt)
             }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
index fc15c0eb4ec..b3fb7123ef3 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
@@ -105,7 +105,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
 
             mc::cat_deref(cmt_base, _, pk) => {
                 match pk {
-                    mc::OwnedPtr => {
+                    mc::Unique => {
                         // R-Deref-Send-Pointer
                         //
                         // When we borrow the interior of an owned pointer, we
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 5be66d42920..513b955da3f 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -281,6 +281,8 @@ struct ModuleConfig {
     time_passes: bool,
 }
 
+unsafe impl Send for ModuleConfig { }
+
 impl ModuleConfig {
     fn new(tm: TargetMachineRef, passes: Vec<String>) -> ModuleConfig {
         ModuleConfig {
diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs
index f829a8ec248..640e83469b2 100644
--- a/src/librustc_trans/trans/debuginfo.rs
+++ b/src/librustc_trans/trans/debuginfo.rs
@@ -216,32 +216,32 @@ use syntax::{ast, codemap, ast_util, ast_map};
 use syntax::ast_util::PostExpansionMethod;
 use syntax::parse::token::{mod, special_idents};
 
-static DW_LANG_RUST: c_uint = 0x9000;
+const DW_LANG_RUST: c_uint = 0x9000;
 
 #[allow(non_upper_case_globals)]
-static DW_TAG_auto_variable: c_uint = 0x100;
+const DW_TAG_auto_variable: c_uint = 0x100;
 #[allow(non_upper_case_globals)]
-static DW_TAG_arg_variable: c_uint = 0x101;
+const DW_TAG_arg_variable: c_uint = 0x101;
 
 #[allow(non_upper_case_globals)]
-static DW_ATE_boolean: c_uint = 0x02;
+const DW_ATE_boolean: c_uint = 0x02;
 #[allow(non_upper_case_globals)]
-static DW_ATE_float: c_uint = 0x04;
+const DW_ATE_float: c_uint = 0x04;
 #[allow(non_upper_case_globals)]
-static DW_ATE_signed: c_uint = 0x05;
+const DW_ATE_signed: c_uint = 0x05;
 #[allow(non_upper_case_globals)]
-static DW_ATE_unsigned: c_uint = 0x07;
+const DW_ATE_unsigned: c_uint = 0x07;
 #[allow(non_upper_case_globals)]
-static DW_ATE_unsigned_char: c_uint = 0x08;
+const DW_ATE_unsigned_char: c_uint = 0x08;
 
-static UNKNOWN_LINE_NUMBER: c_uint = 0;
-static UNKNOWN_COLUMN_NUMBER: c_uint = 0;
+const UNKNOWN_LINE_NUMBER: c_uint = 0;
+const UNKNOWN_COLUMN_NUMBER: c_uint = 0;
 
 // ptr::null() doesn't work :(
-static UNKNOWN_FILE_METADATA: DIFile = (0 as DIFile);
-static UNKNOWN_SCOPE_METADATA: DIScope = (0 as DIScope);
+const UNKNOWN_FILE_METADATA: DIFile = (0 as DIFile);
+const UNKNOWN_SCOPE_METADATA: DIScope = (0 as DIScope);
 
-static FLAGS_NONE: c_uint = 0;
+const FLAGS_NONE: c_uint = 0;
 
 //=-----------------------------------------------------------------------------
 //  Public Interface of debuginfo module
diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs
index 4b1b92b552c..c53e164fb07 100644
--- a/src/librustc_trans/trans/mod.rs
+++ b/src/librustc_trans/trans/mod.rs
@@ -60,6 +60,9 @@ pub struct ModuleTranslation {
     pub llmod: ModuleRef,
 }
 
+unsafe impl Send for ModuleTranslation { }
+unsafe impl Sync for ModuleTranslation { }
+
 pub struct CrateTranslation {
     pub modules: Vec<ModuleTranslation>,
     pub metadata_module: ModuleTranslation,
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 429eee87026..e17cf81baa8 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -1403,7 +1403,7 @@ fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
             }
 
             mc::cat_downcast(cmt_base, _) |
-            mc::cat_deref(cmt_base, _, mc::OwnedPtr) |
+            mc::cat_deref(cmt_base, _, mc::Unique) |
             mc::cat_interior(cmt_base, _) => {
                 // Borrowing interior or owned data requires the base
                 // to be valid and borrowable in the same fashion.
@@ -1627,7 +1627,7 @@ fn adjust_upvar_borrow_kind_for_mut<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
                cmt.repr(rcx.tcx()));
 
         match cmt.cat.clone() {
-            mc::cat_deref(base, _, mc::OwnedPtr) |
+            mc::cat_deref(base, _, mc::Unique) |
             mc::cat_interior(base, _) |
             mc::cat_downcast(base, _) => {
                 // Interior or owned data is mutable if base is
@@ -1674,7 +1674,7 @@ fn adjust_upvar_borrow_kind_for_unique<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, cmt: mc::c
                cmt.repr(rcx.tcx()));
 
         match cmt.cat.clone() {
-            mc::cat_deref(base, _, mc::OwnedPtr) |
+            mc::cat_deref(base, _, mc::Unique) |
             mc::cat_interior(base, _) |
             mc::cat_downcast(base, _) => {
                 // Interior or owned data is unique if base is
diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs
index e23bf46b564..7ebf39e2e9a 100644
--- a/src/librustc_typeck/check/vtable.rs
+++ b/src/librustc_typeck/check/vtable.rs
@@ -11,16 +11,14 @@
 use check::{FnCtxt, structurally_resolved_type};
 use middle::subst::{FnSpace};
 use middle::traits;
-use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented};
 use middle::traits::{Obligation, ObligationCause};
-use middle::traits::{FulfillmentError, CodeSelectionError, CodeAmbiguity};
-use middle::traits::{PredicateObligation};
+use middle::traits::report_fulfillment_errors;
 use middle::ty::{mod, Ty};
 use middle::infer;
 use std::rc::Rc;
 use syntax::ast;
 use syntax::codemap::Span;
-use util::ppaux::{UserString, Repr, ty_to_string};
+use util::ppaux::{Repr, ty_to_string};
 
 pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                    cast_expr: &ast::Expr,
@@ -285,199 +283,7 @@ pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
                                                fcx);
     match r {
         Ok(()) => { }
-        Err(errors) => { report_fulfillment_errors(fcx, &errors); }
-    }
-}
-
-pub fn report_fulfillment_errors<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                           errors: &Vec<FulfillmentError<'tcx>>) {
-    for error in errors.iter() {
-        report_fulfillment_error(fcx, error);
-    }
-}
-
-pub fn report_fulfillment_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                          error: &FulfillmentError<'tcx>) {
-    match error.code {
-        CodeSelectionError(ref e) => {
-            report_selection_error(fcx, &error.obligation, e);
-        }
-        CodeAmbiguity => {
-            maybe_report_ambiguity(fcx, &error.obligation);
-        }
-    }
-}
-
-pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                        obligation: &PredicateObligation<'tcx>,
-                                        error: &SelectionError<'tcx>)
-{
-    match *error {
-        Overflow => {
-            // We could track the stack here more precisely if we wanted, I imagine.
-            let predicate =
-                fcx.infcx().resolve_type_vars_if_possible(&obligation.trait_ref);
-            fcx.tcx().sess.span_err(
-                obligation.cause.span,
-                format!(
-                    "overflow evaluating the requirement `{}`",
-                    predicate.user_string(fcx.tcx())).as_slice());
-
-            let current_limit = fcx.tcx().sess.recursion_limit.get();
-            let suggested_limit = current_limit * 2;
-            fcx.tcx().sess.span_note(
-                obligation.cause.span,
-                format!(
-                    "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
-                    suggested_limit)[]);
-
-            note_obligation_cause(fcx, obligation);
-        }
-        Unimplemented => {
-            match obligation.trait_ref {
-                ty::Predicate::Trait(ref trait_ref) => {
-                    let trait_ref = fcx.infcx().resolve_type_vars_if_possible(&**trait_ref);
-                    if !ty::type_is_error(trait_ref.self_ty()) {
-                        fcx.tcx().sess.span_err(
-                            obligation.cause.span,
-                            format!(
-                                "the trait `{}` is not implemented for the type `{}`",
-                                trait_ref.user_string(fcx.tcx()),
-                                trait_ref.self_ty().user_string(fcx.tcx())).as_slice());
-                    }
-                }
-
-                ty::Predicate::Equate(ref predicate) => {
-                    let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate);
-                    let err = fcx.infcx().equality_predicate(obligation.cause.span,
-                                                             &predicate).unwrap_err();
-                    fcx.tcx().sess.span_err(
-                        obligation.cause.span,
-                        format!(
-                            "the requirement `{}` is not satisfied (`{}`)",
-                            predicate.user_string(fcx.tcx()),
-                            ty::type_err_to_str(fcx.tcx(), &err)).as_slice());
-                }
-
-                ty::Predicate::RegionOutlives(ref predicate) => {
-                    let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate);
-                    let err = fcx.infcx().region_outlives_predicate(obligation.cause.span,
-                                                                    &predicate).unwrap_err();
-                    fcx.tcx().sess.span_err(
-                        obligation.cause.span,
-                        format!(
-                            "the requirement `{}` is not satisfied (`{}`)",
-                            predicate.user_string(fcx.tcx()),
-                            ty::type_err_to_str(fcx.tcx(), &err)).as_slice());
-                }
-
-                ty::Predicate::TypeOutlives(ref predicate) => {
-                    let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate);
-                    fcx.tcx().sess.span_err(
-                        obligation.cause.span,
-                        format!(
-                            "the requirement `{}` is not satisfied",
-                            predicate.user_string(fcx.tcx())).as_slice());
-                }
-            }
-
-            note_obligation_cause(fcx, obligation);
-        }
-        OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
-            let expected_trait_ref =
-                fcx.infcx().resolve_type_vars_if_possible(
-                    &**expected_trait_ref);
-            let actual_trait_ref =
-                fcx.infcx().resolve_type_vars_if_possible(
-                    &**actual_trait_ref);
-            if !ty::type_is_error(actual_trait_ref.self_ty()) {
-                fcx.tcx().sess.span_err(
-                    obligation.cause.span,
-                    format!(
-                        "type mismatch: the type `{}` implements the trait `{}`, \
-                         but the trait `{}` is required ({})",
-                        expected_trait_ref.self_ty().user_string(fcx.tcx()),
-                        expected_trait_ref.user_string(fcx.tcx()),
-                        actual_trait_ref.user_string(fcx.tcx()),
-                        ty::type_err_to_str(fcx.tcx(), e)).as_slice());
-                note_obligation_cause(fcx, obligation);
-            }
-        }
-    }
-}
-
-pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                        obligation: &PredicateObligation<'tcx>) {
-    // Unable to successfully determine, probably means
-    // insufficient type information, but could mean
-    // ambiguous impls. The latter *ought* to be a
-    // coherence violation, so we don't report it here.
-
-    let trait_ref = match obligation.trait_ref {
-        ty::Predicate::Trait(ref trait_ref) => {
-            fcx.infcx().resolve_type_vars_if_possible(&**trait_ref)
-        }
-        _ => {
-            fcx.tcx().sess.span_bug(
-                obligation.cause.span,
-                format!("ambiguity from something other than a trait: {}",
-                        obligation.trait_ref.repr(fcx.tcx())).as_slice());
-        }
-    };
-    let self_ty = trait_ref.self_ty();
-
-    debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})",
-           trait_ref.repr(fcx.tcx()),
-           self_ty.repr(fcx.tcx()),
-           obligation.repr(fcx.tcx()));
-    let all_types = &trait_ref.substs().types;
-    if all_types.iter().any(|&t| ty::type_is_error(t)) {
-    } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) {
-        // This is kind of a hack: it frequently happens that some earlier
-        // error prevents types from being fully inferred, and then we get
-        // a bunch of uninteresting errors saying something like "<generic
-        // #0> doesn't implement Sized".  It may even be true that we
-        // could just skip over all checks where the self-ty is an
-        // inference variable, but I was afraid that there might be an
-        // inference variable created, registered as an obligation, and
-        // then never forced by writeback, and hence by skipping here we'd
-        // be ignoring the fact that we don't KNOW the type works
-        // out. Though even that would probably be harmless, given that
-        // we're only talking about builtin traits, which are known to be
-        // inhabited. But in any case I just threw in this check for
-        // has_errors() to be sure that compilation isn't happening
-        // anyway. In that case, why inundate the user.
-        if !fcx.tcx().sess.has_errors() {
-            if fcx.ccx.tcx.lang_items.sized_trait()
-                  .map_or(false, |sized_id| sized_id == trait_ref.def_id()) {
-                fcx.tcx().sess.span_err(
-                    obligation.cause.span,
-                    format!(
-                        "unable to infer enough type information about `{}`; type annotations \
-                         required",
-                        self_ty.user_string(fcx.tcx()))[]);
-            } else {
-                fcx.tcx().sess.span_err(
-                    obligation.cause.span,
-                    format!(
-                        "unable to infer enough type information to \
-                         locate the impl of the trait `{}` for \
-                         the type `{}`; type annotations required",
-                        trait_ref.user_string(fcx.tcx()),
-                        self_ty.user_string(fcx.tcx()))[]);
-                note_obligation_cause(fcx, obligation);
-            }
-        }
-    } else if !fcx.tcx().sess.has_errors() {
-         // Ambiguity. Coherence should have reported an error.
-        fcx.tcx().sess.span_bug(
-            obligation.cause.span,
-            format!(
-                "coherence failed to report ambiguity: \
-                 cannot locate the impl of the trait `{}` for \
-                 the type `{}`",
-                trait_ref.user_string(fcx.tcx()),
-                self_ty.user_string(fcx.tcx()))[]);
+        Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
     }
 }
 
@@ -490,7 +296,7 @@ pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt)
         .select_where_possible(fcx.infcx(), &fcx.inh.param_env, fcx)
     {
         Ok(()) => { }
-        Err(errors) => { report_fulfillment_errors(fcx, &errors); }
+        Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
     }
 }
 
@@ -504,83 +310,6 @@ pub fn select_new_fcx_obligations(fcx: &FnCtxt) {
         .select_new_obligations(fcx.infcx(), &fcx.inh.param_env, fcx)
     {
         Ok(()) => { }
-        Err(errors) => { report_fulfillment_errors(fcx, &errors); }
-    }
-}
-
-fn note_obligation_cause<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                   obligation: &PredicateObligation<'tcx>) {
-    let tcx = fcx.tcx();
-    match obligation.cause.code {
-        traits::MiscObligation => { }
-        traits::ItemObligation(item_def_id) => {
-            let item_name = ty::item_path_str(tcx, item_def_id);
-            tcx.sess.span_note(
-                obligation.cause.span,
-                format!(
-                    "required by `{}`",
-                    item_name).as_slice());
-        }
-        traits::ObjectCastObligation(object_ty) => {
-            tcx.sess.span_note(
-                obligation.cause.span,
-                format!(
-                    "required for the cast to the object type `{}`",
-                    fcx.infcx().ty_to_string(object_ty)).as_slice());
-        }
-        traits::RepeatVec => {
-            tcx.sess.span_note(
-                obligation.cause.span,
-                "the `Copy` trait is required because the \
-                 repeated element will be copied");
-        }
-        traits::VariableType(_) => {
-            tcx.sess.span_note(
-                obligation.cause.span,
-                "all local variables must have a statically known size");
-        }
-        traits::ReturnType => {
-            tcx.sess.span_note(
-                obligation.cause.span,
-                "the return type of a function must have a \
-                 statically known size");
-        }
-        traits::AssignmentLhsSized => {
-            tcx.sess.span_note(
-                obligation.cause.span,
-                "the left-hand-side of an assignment must have a statically known size");
-        }
-        traits::StructInitializerSized => {
-            tcx.sess.span_note(
-                obligation.cause.span,
-                "structs must have a statically known size to be initialized");
-        }
-        traits::DropTrait => {
-            span_note!(tcx.sess, obligation.cause.span,
-                      "cannot implement a destructor on a \
-                      structure or enumeration that does not satisfy Send");
-            span_help!(tcx.sess, obligation.cause.span,
-                       "use \"#[unsafe_destructor]\" on the implementation \
-                       to force the compiler to allow this");
-        }
-        traits::ClosureCapture(var_id, closure_span, builtin_bound) => {
-            let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap();
-            let trait_name = ty::item_path_str(tcx, def_id);
-            let name = ty::local_var_name_str(tcx, var_id);
-            span_note!(tcx.sess, closure_span,
-                       "the closure that captures `{}` requires that all captured variables \"
-                       implement the trait `{}`",
-                       name,
-                       trait_name);
-        }
-        traits::FieldSized => {
-            span_note!(tcx.sess, obligation.cause.span,
-                       "only the last field of a struct or enum variant \
-                       may have a dynamically sized type")
-        }
-        traits::ObjectSized => {
-            span_note!(tcx.sess, obligation.cause.span,
-                       "only sized types can be made into objects");
-        }
+        Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
     }
 }
diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs
index a2fb44fff79..39bcfb354b8 100644
--- a/src/librustc_typeck/check/wf.rs
+++ b/src/librustc_typeck/check/wf.rs
@@ -188,7 +188,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                 match self_ty.sty {
                     ty::ty_struct(def_id, _) |
                     ty::ty_enum(def_id, _) => {
-                        check_struct_safe_for_destructor(fcx, item.span, self_ty, def_id);
+                        check_struct_safe_for_destructor(fcx, item.span, def_id);
                     }
                     _ => {
                         // Coherence already reports an error in this case.
@@ -221,7 +221,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             let poly_trait_ref = ty::Binder(trait_ref);
             let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &poly_trait_ref);
             for predicate in predicates.into_iter() {
-                fcx.register_predicate(traits::Obligation::new(cause, predicate));
+                fcx.register_predicate(traits::Obligation::new(cause.clone(), predicate));
             }
         });
     }
@@ -460,20 +460,16 @@ fn filter_to_trait_obligations<'tcx>(bounds: ty::GenericBounds<'tcx>)
 
 fn check_struct_safe_for_destructor<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                               span: Span,
-                                              self_ty: Ty<'tcx>,
                                               struct_did: ast::DefId) {
     let struct_tpt = ty::lookup_item_type(fcx.tcx(), struct_did);
-    if !struct_tpt.generics.has_type_params(subst::TypeSpace)
-        && !struct_tpt.generics.has_region_params(subst::TypeSpace)
+    if struct_tpt.generics.has_type_params(subst::TypeSpace)
+        || struct_tpt.generics.has_region_params(subst::TypeSpace)
     {
-        let cause = traits::ObligationCause::new(span, fcx.body_id, traits::DropTrait);
-        fcx.register_builtin_bound(self_ty, ty::BoundSend, cause);
-    } else {
         span_err!(fcx.tcx().sess, span, E0141,
                   "cannot implement a destructor on a structure \
-                       with type parameters");
-            span_note!(fcx.tcx().sess, span,
-                       "use \"#[unsafe_destructor]\" on the implementation \
-                        to force the compiler to allow this");
+                   with type parameters");
+        span_note!(fcx.tcx().sess, span,
+                   "use \"#[unsafe_destructor]\" on the implementation \
+                    to force the compiler to allow this");
     }
 }
diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs
index fb369924c64..ffe19203769 100644
--- a/src/libstd/c_str.rs
+++ b/src/libstd/c_str.rs
@@ -72,13 +72,12 @@ use libc;
 
 use fmt;
 use hash;
-use kinds::marker;
 use mem;
 use ptr;
 use slice::{mod, ImmutableIntSlice};
 use str;
 use string::String;
-
+use core::kinds::marker;
 
 /// The representation of a C String.
 ///
@@ -90,6 +89,9 @@ pub struct CString {
     owns_buffer_: bool,
 }
 
+unsafe impl Send for CString { }
+unsafe impl Sync for CString { }
+
 impl Clone for CString {
     /// Clone this CString into a new, uniquely owned CString. For safety
     /// reasons, this is always a deep clone with the memory allocated
diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs
index 44e7291150e..f4338815f75 100644
--- a/src/libstd/c_vec.rs
+++ b/src/libstd/c_vec.rs
@@ -180,12 +180,12 @@ mod tests {
 
     fn malloc(n: uint) -> CVec<u8> {
         unsafe {
-            let mem = libc::malloc(n as libc::size_t);
-            if mem.is_null() { ::alloc::oom() }
+            let mem = ptr::Unique(libc::malloc(n as libc::size_t));
+            if mem.0.is_null() { ::alloc::oom() }
 
-            CVec::new_with_dtor(mem as *mut u8,
+            CVec::new_with_dtor(mem.0 as *mut u8,
                                 n,
-                                move|| { libc::free(mem as *mut libc::c_void); })
+                                move|| { libc::free(mem.0 as *mut libc::c_void); })
         }
     }
 
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index 8f2152c5a9d..3ae3a8ffbad 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -23,7 +23,7 @@ use num::{Int, UnsignedInt};
 use ops::{Deref, DerefMut, Drop};
 use option::Option;
 use option::Option::{Some, None};
-use ptr::{RawPtr, copy_nonoverlapping_memory, zero_memory};
+use ptr::{Unique, RawPtr, copy_nonoverlapping_memory, zero_memory};
 use ptr;
 use rt::heap::{allocate, deallocate};
 
@@ -69,7 +69,7 @@ const EMPTY_BUCKET: u64 = 0u64;
 pub struct RawTable<K, V> {
     capacity: uint,
     size:     uint,
-    hashes:   *mut u64,
+    hashes:   Unique<u64>,
     // Because K/V do not appear directly in any of the types in the struct,
     // inform rustc that in fact instances of K and V are reachable from here.
     marker:   marker::CovariantType<(K,V)>,
@@ -563,7 +563,7 @@ impl<K, V> RawTable<K, V> {
             return RawTable {
                 size: 0,
                 capacity: 0,
-                hashes: 0 as *mut u64,
+                hashes: Unique::null(),
                 marker: marker::CovariantType,
             };
         }
@@ -602,7 +602,7 @@ impl<K, V> RawTable<K, V> {
         RawTable {
             capacity: capacity,
             size:     0,
-            hashes:   hashes,
+            hashes:   Unique(hashes),
             marker:   marker::CovariantType,
         }
     }
@@ -611,14 +611,14 @@ impl<K, V> RawTable<K, V> {
         let hashes_size = self.capacity * size_of::<u64>();
         let keys_size = self.capacity * size_of::<K>();
 
-        let buffer = self.hashes as *mut u8;
+        let buffer = self.hashes.0 as *mut u8;
         let (keys_offset, vals_offset) = calculate_offsets(hashes_size,
                                                            keys_size, min_align_of::<K>(),
                                                            min_align_of::<V>());
 
         unsafe {
             RawBucket {
-                hash: self.hashes,
+                hash: self.hashes.0,
                 key:  buffer.offset(keys_offset as int) as *mut K,
                 val:  buffer.offset(vals_offset as int) as *mut V
             }
@@ -631,7 +631,7 @@ impl<K, V> RawTable<K, V> {
     pub fn new(capacity: uint) -> RawTable<K, V> {
         unsafe {
             let ret = RawTable::new_uninitialized(capacity);
-            zero_memory(ret.hashes, capacity);
+            zero_memory(ret.hashes.0, capacity);
             ret
         }
     }
@@ -651,7 +651,7 @@ impl<K, V> RawTable<K, V> {
         RawBuckets {
             raw: self.first_bucket_raw(),
             hashes_end: unsafe {
-                self.hashes.offset(self.capacity as int)
+                self.hashes.0.offset(self.capacity as int)
             },
             marker: marker::ContravariantLifetime,
         }
@@ -916,7 +916,7 @@ impl<K: Clone, V: Clone> Clone for RawTable<K, V> {
 #[unsafe_destructor]
 impl<K, V> Drop for RawTable<K, V> {
     fn drop(&mut self) {
-        if self.hashes.is_null() {
+        if self.hashes.0.is_null() {
             return;
         }
         // This is done in reverse because we've likely partially taken
@@ -936,7 +936,7 @@ impl<K, V> Drop for RawTable<K, V> {
                                                     vals_size, min_align_of::<V>());
 
         unsafe {
-            deallocate(self.hashes as *mut u8, size, align);
+            deallocate(self.hashes.0 as *mut u8, size, align);
             // Remember how everything was allocated out of one buffer
             // during initialization? We only need one call to free here.
         }
diff --git a/src/libstd/comm/blocking.rs b/src/libstd/comm/blocking.rs
index c477acd70aa..412b7161305 100644
--- a/src/libstd/comm/blocking.rs
+++ b/src/libstd/comm/blocking.rs
@@ -13,6 +13,7 @@
 use thread::Thread;
 use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Ordering};
 use sync::Arc;
+use kinds::{Sync, Send};
 use kinds::marker::{NoSend, NoSync};
 use mem;
 use clone::Clone;
@@ -22,6 +23,9 @@ struct Inner {
     woken: AtomicBool,
 }
 
+unsafe impl Send for Inner {}
+unsafe impl Sync for Inner {}
+
 #[deriving(Clone)]
 pub struct SignalToken {
     inner: Arc<Inner>,
diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs
index d3bfaab83da..c85bea87218 100644
--- a/src/libstd/comm/mod.rs
+++ b/src/libstd/comm/mod.rs
@@ -319,6 +319,7 @@ pub use self::TrySendError::*;
 use self::Flavor::*;
 
 use alloc::arc::Arc;
+use core::kinds;
 use core::kinds::marker;
 use core::mem;
 use core::cell::UnsafeCell;
@@ -357,10 +358,12 @@ mod spsc_queue;
 #[unstable]
 pub struct Receiver<T> {
     inner: UnsafeCell<Flavor<T>>,
-    // can't share in an arc
-    _marker: marker::NoSync,
 }
 
+// The receiver port can be sent from place to place, so long as it
+// is not used to receive non-sendable things.
+unsafe impl<T:Send> Send for Receiver<T> { }
+
 /// An iterator over messages on a receiver, this iterator will block
 /// whenever `next` is called, waiting for a new message, and `None` will be
 /// returned when the corresponding channel has hung up.
@@ -374,15 +377,17 @@ pub struct Messages<'a, T:'a> {
 #[unstable]
 pub struct Sender<T> {
     inner: UnsafeCell<Flavor<T>>,
-    // can't share in an arc
-    _marker: marker::NoSync,
 }
 
+// The send port can be sent from place to place, so long as it
+// is not used to send non-sendable things.
+unsafe impl<T:Send> Send for Sender<T> { }
+
 /// The sending-half of Rust's synchronous channel type. This half can only be
 /// owned by one task, but it can be cloned to send to other tasks.
 #[unstable = "this type may be renamed, but it will always exist"]
 pub struct SyncSender<T> {
-    inner: Arc<UnsafeCell<sync::Packet<T>>>,
+    inner: Arc<RacyCell<sync::Packet<T>>>,
     // can't share in an arc
     _marker: marker::NoSync,
 }
@@ -418,10 +423,10 @@ pub enum TrySendError<T> {
 }
 
 enum Flavor<T> {
-    Oneshot(Arc<UnsafeCell<oneshot::Packet<T>>>),
-    Stream(Arc<UnsafeCell<stream::Packet<T>>>),
-    Shared(Arc<UnsafeCell<shared::Packet<T>>>),
-    Sync(Arc<UnsafeCell<sync::Packet<T>>>),
+    Oneshot(Arc<RacyCell<oneshot::Packet<T>>>),
+    Stream(Arc<RacyCell<stream::Packet<T>>>),
+    Shared(Arc<RacyCell<shared::Packet<T>>>),
+    Sync(Arc<RacyCell<sync::Packet<T>>>),
 }
 
 #[doc(hidden)]
@@ -472,7 +477,7 @@ impl<T> UnsafeFlavor<T> for Receiver<T> {
 /// ```
 #[unstable]
 pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) {
-    let a = Arc::new(UnsafeCell::new(oneshot::Packet::new()));
+    let a = Arc::new(RacyCell::new(oneshot::Packet::new()));
     (Sender::new(Oneshot(a.clone())), Receiver::new(Oneshot(a)))
 }
 
@@ -512,7 +517,7 @@ pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) {
 #[unstable = "this function may be renamed to more accurately reflect the type \
               of channel that is is creating"]
 pub fn sync_channel<T: Send>(bound: uint) -> (SyncSender<T>, Receiver<T>) {
-    let a = Arc::new(UnsafeCell::new(sync::Packet::new(bound)));
+    let a = Arc::new(RacyCell::new(sync::Packet::new(bound)));
     (SyncSender::new(a.clone()), Receiver::new(Sync(a)))
 }
 
@@ -524,7 +529,6 @@ impl<T: Send> Sender<T> {
     fn new(inner: Flavor<T>) -> Sender<T> {
         Sender {
             inner: UnsafeCell::new(inner),
-            _marker: marker::NoSync,
         }
     }
 
@@ -594,7 +598,8 @@ impl<T: Send> Sender<T> {
                     if !(*p).sent() {
                         return (*p).send(t);
                     } else {
-                        let a = Arc::new(UnsafeCell::new(stream::Packet::new()));
+                        let a =
+                            Arc::new(RacyCell::new(stream::Packet::new()));
                         match (*p).upgrade(Receiver::new(Stream(a.clone()))) {
                             oneshot::UpSuccess => {
                                 let ret = (*a.get()).send(t);
@@ -631,7 +636,7 @@ impl<T: Send> Clone for Sender<T> {
     fn clone(&self) -> Sender<T> {
         let (packet, sleeper, guard) = match *unsafe { self.inner() } {
             Oneshot(ref p) => {
-                let a = Arc::new(UnsafeCell::new(shared::Packet::new()));
+                let a = Arc::new(RacyCell::new(shared::Packet::new()));
                 unsafe {
                     let guard = (*a.get()).postinit_lock();
                     match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) {
@@ -642,7 +647,7 @@ impl<T: Send> Clone for Sender<T> {
                 }
             }
             Stream(ref p) => {
-                let a = Arc::new(UnsafeCell::new(shared::Packet::new()));
+                let a = Arc::new(RacyCell::new(shared::Packet::new()));
                 unsafe {
                     let guard = (*a.get()).postinit_lock();
                     match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) {
@@ -686,7 +691,7 @@ impl<T: Send> Drop for Sender<T> {
 ////////////////////////////////////////////////////////////////////////////////
 
 impl<T: Send> SyncSender<T> {
-    fn new(inner: Arc<UnsafeCell<sync::Packet<T>>>) -> SyncSender<T> {
+    fn new(inner: Arc<RacyCell<sync::Packet<T>>>) -> SyncSender<T> {
         SyncSender { inner: inner, _marker: marker::NoSync }
     }
 
@@ -775,7 +780,7 @@ impl<T: Send> Drop for SyncSender<T> {
 
 impl<T: Send> Receiver<T> {
     fn new(inner: Flavor<T>) -> Receiver<T> {
-        Receiver { inner: UnsafeCell::new(inner), _marker: marker::NoSync }
+        Receiver { inner: UnsafeCell::new(inner) }
     }
 
     /// Blocks waiting for a value on this receiver
@@ -1018,6 +1023,27 @@ impl<T: Send> Drop for Receiver<T> {
     }
 }
 
+/// A version of `UnsafeCell` intended for use in concurrent data
+/// structures (for example, you might put it in an `Arc`).
+struct RacyCell<T>(pub UnsafeCell<T>);
+
+impl<T> RacyCell<T> {
+
+    fn new(value: T) -> RacyCell<T> {
+        RacyCell(UnsafeCell { value: value })
+    }
+
+    unsafe fn get(&self) -> *mut T {
+        self.0.get()
+    }
+
+}
+
+unsafe impl<T:Send> Send for RacyCell<T> { }
+
+unsafe impl<T> kinds::Sync for RacyCell<T> { } // Oh dear
+
+
 #[cfg(test)]
 mod test {
     use super::*;
diff --git a/src/libstd/comm/mpsc_queue.rs b/src/libstd/comm/mpsc_queue.rs
index db4e3eac449..cddef236664 100644
--- a/src/libstd/comm/mpsc_queue.rs
+++ b/src/libstd/comm/mpsc_queue.rs
@@ -76,6 +76,9 @@ pub struct Queue<T> {
     tail: UnsafeCell<*mut Node<T>>,
 }
 
+unsafe impl<T:Send> Send for Queue<T> { }
+unsafe impl<T:Send> Sync for Queue<T> { }
+
 impl<T> Node<T> {
     unsafe fn new(v: Option<T>) -> *mut Node<T> {
         mem::transmute(box Node {
diff --git a/src/libstd/comm/spsc_queue.rs b/src/libstd/comm/spsc_queue.rs
index db8fff772a4..becb78063ae 100644
--- a/src/libstd/comm/spsc_queue.rs
+++ b/src/libstd/comm/spsc_queue.rs
@@ -73,6 +73,10 @@ pub struct Queue<T> {
     cache_subtractions: AtomicUint,
 }
 
+unsafe impl<T: Send> Send for Queue<T> { }
+
+unsafe impl<T: Send> Sync for Queue<T> { }
+
 impl<T: Send> Node<T> {
     fn new() -> *mut Node<T> {
         unsafe {
diff --git a/src/libstd/comm/sync.rs b/src/libstd/comm/sync.rs
index f75186e70e3..88338849965 100644
--- a/src/libstd/comm/sync.rs
+++ b/src/libstd/comm/sync.rs
@@ -53,6 +53,10 @@ pub struct Packet<T> {
     lock: Mutex<State<T>>,
 }
 
+unsafe impl<T:Send> Send for Packet<T> { }
+
+unsafe impl<T:Send> Sync for Packet<T> { }
+
 struct State<T> {
     disconnected: bool, // Is the channel disconnected yet?
     queue: Queue,       // queue of senders waiting to send data
@@ -69,6 +73,8 @@ struct State<T> {
     canceled: Option<&'static mut bool>,
 }
 
+unsafe impl<T: Send> Send for State<T> {}
+
 /// Possible flavors of threads who can be blocked on this channel.
 enum Blocker {
     BlockedSender(SignalToken),
@@ -88,6 +94,8 @@ struct Node {
     next: *mut Node,
 }
 
+unsafe impl Send for Node {}
+
 /// A simple ring-buffer
 struct Buffer<T> {
     buf: Vec<Option<T>>,
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 9d9e8827571..c26450310a9 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -22,6 +22,7 @@ use result::Result::{Ok, Err};
 use slice::{SliceExt};
 use slice;
 use vec::Vec;
+use kinds::{Send,Sync};
 
 /// Wraps a Reader and buffers input from it
 ///
@@ -51,6 +52,11 @@ pub struct BufferedReader<R> {
     cap: uint,
 }
 
+
+unsafe impl<R: Send> Send for BufferedReader<R> {}
+unsafe impl<R: Send+Sync> Sync for BufferedReader<R> {}
+
+
 impl<R: Reader> BufferedReader<R> {
     /// Creates a new `BufferedReader` with the specified buffer capacity
     pub fn with_capacity(cap: uint, inner: R) -> BufferedReader<R> {
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index 1c5ceaf2450..b7da57fed27 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -34,7 +34,7 @@ use failure::LOCAL_STDERR;
 use fmt;
 use io::{Reader, Writer, IoResult, IoError, OtherIoError, Buffer,
          standard_error, EndOfFile, LineBufferedWriter, BufferedReader};
-use kinds::Send;
+use kinds::{Sync, Send};
 use libc;
 use mem;
 use option::Option;
@@ -98,26 +98,34 @@ thread_local! {
     }
 }
 
+struct RaceBox(BufferedReader<StdReader>);
+
+unsafe impl Send for RaceBox {}
+unsafe impl Sync for RaceBox {}
+
 /// A synchronized wrapper around a buffered reader from stdin
 #[deriving(Clone)]
 pub struct StdinReader {
-    inner: Arc<Mutex<BufferedReader<StdReader>>>,
+    inner: Arc<Mutex<RaceBox>>,
 }
 
+unsafe impl Send for StdinReader {}
+unsafe impl Sync for StdinReader {}
+
 /// A guard for exclusive access to `StdinReader`'s internal `BufferedReader`.
 pub struct StdinReaderGuard<'a> {
-    inner: MutexGuard<'a, BufferedReader<StdReader>>,
+    inner: MutexGuard<'a, RaceBox>,
 }
 
 impl<'a> Deref<BufferedReader<StdReader>> for StdinReaderGuard<'a> {
     fn deref(&self) -> &BufferedReader<StdReader> {
-        &*self.inner
+        &self.inner.0
     }
 }
 
 impl<'a> DerefMut<BufferedReader<StdReader>> for StdinReaderGuard<'a> {
     fn deref_mut(&mut self) -> &mut BufferedReader<StdReader> {
-        &mut *self.inner
+        &mut self.inner.0
     }
 }
 
@@ -147,7 +155,7 @@ impl StdinReader {
     /// The read is performed atomically - concurrent read calls in other
     /// threads will not interleave with this one.
     pub fn read_line(&mut self) -> IoResult<String> {
-        self.inner.lock().read_line()
+        self.inner.lock().0.read_line()
     }
 
     /// Like `Buffer::read_until`.
@@ -155,7 +163,7 @@ impl StdinReader {
     /// The read is performed atomically - concurrent read calls in other
     /// threads will not interleave with this one.
     pub fn read_until(&mut self, byte: u8) -> IoResult<Vec<u8>> {
-        self.inner.lock().read_until(byte)
+        self.inner.lock().0.read_until(byte)
     }
 
     /// Like `Buffer::read_char`.
@@ -163,13 +171,13 @@ impl StdinReader {
     /// The read is performed atomically - concurrent read calls in other
     /// threads will not interleave with this one.
     pub fn read_char(&mut self) -> IoResult<char> {
-        self.inner.lock().read_char()
+        self.inner.lock().0.read_char()
     }
 }
 
 impl Reader for StdinReader {
     fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        self.inner.lock().read(buf)
+        self.inner.lock().0.read(buf)
     }
 
     // We have to manually delegate all of these because the default impls call
@@ -177,23 +185,23 @@ impl Reader for StdinReader {
     // incur the costs of repeated locking).
 
     fn read_at_least(&mut self, min: uint, buf: &mut [u8]) -> IoResult<uint> {
-        self.inner.lock().read_at_least(min, buf)
+        self.inner.lock().0.read_at_least(min, buf)
     }
 
     fn push_at_least(&mut self, min: uint, len: uint, buf: &mut Vec<u8>) -> IoResult<uint> {
-        self.inner.lock().push_at_least(min, len, buf)
+        self.inner.lock().0.push_at_least(min, len, buf)
     }
 
     fn read_to_end(&mut self) -> IoResult<Vec<u8>> {
-        self.inner.lock().read_to_end()
+        self.inner.lock().0.read_to_end()
     }
 
     fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult<u64> {
-        self.inner.lock().read_le_uint_n(nbytes)
+        self.inner.lock().0.read_le_uint_n(nbytes)
     }
 
     fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult<u64> {
-        self.inner.lock().read_be_uint_n(nbytes)
+        self.inner.lock().0.read_be_uint_n(nbytes)
     }
 }
 
@@ -221,7 +229,7 @@ pub fn stdin() -> StdinReader {
                 BufferedReader::new(stdin_raw())
             };
             let stdin = StdinReader {
-                inner: Arc::new(Mutex::new(stdin))
+                inner: Arc::new(Mutex::new(RaceBox(stdin)))
             };
             STDIN = mem::transmute(box stdin);
 
@@ -426,6 +434,9 @@ pub struct StdWriter {
     inner: StdSource
 }
 
+unsafe impl Send for StdWriter {}
+unsafe impl Sync for StdWriter {}
+
 impl StdWriter {
     /// Gets the size of this output window, if possible. This is typically used
     /// when the writer is attached to something like a terminal, this is used
diff --git a/src/libstd/rt/exclusive.rs b/src/libstd/rt/exclusive.rs
index 1d3082d1b4c..88bdb29caec 100644
--- a/src/libstd/rt/exclusive.rs
+++ b/src/libstd/rt/exclusive.rs
@@ -26,6 +26,10 @@ pub struct Exclusive<T> {
     data: UnsafeCell<T>,
 }
 
+unsafe impl<T:Send> Send for Exclusive<T> { }
+
+unsafe impl<T:Send> Sync for Exclusive<T> { }
+
 /// An RAII guard returned via `lock`
 pub struct ExclusiveGuard<'a, T:'a> {
     // FIXME #12808: strange name to try to avoid interfering with
diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs
index 6573d9273ce..6cdb199819a 100644
--- a/src/libstd/sync/barrier.rs
+++ b/src/libstd/sync/barrier.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use kinds::{Send, Sync};
 use sync::{Mutex, Condvar};
 
 /// A barrier enables multiple tasks to synchronize the beginning
@@ -35,12 +36,18 @@ pub struct Barrier {
     num_threads: uint,
 }
 
+unsafe impl Send for Barrier {}
+unsafe impl Sync for Barrier {}
+
 // The inner state of a double barrier
 struct BarrierState {
     count: uint,
     generation_id: uint,
 }
 
+unsafe impl Send for BarrierState {}
+unsafe impl Sync for BarrierState {}
+
 impl Barrier {
     /// Create a new barrier that can block a given number of threads.
     ///
diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index be27c06b83c..f1940bfd829 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -58,6 +58,9 @@ use time::Duration;
 /// ```
 pub struct Condvar { inner: Box<StaticCondvar> }
 
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
 /// Statically allocated condition variables.
 ///
 /// This structure is identical to `Condvar` except that it is suitable for use
@@ -75,6 +78,9 @@ pub struct StaticCondvar {
     mutex: AtomicUint,
 }
 
+unsafe impl Send for StaticCondvar {}
+unsafe impl Sync for StaticCondvar {}
+
 /// Constant initializer for a statically allocated condition variable.
 pub const CONDVAR_INIT: StaticCondvar = StaticCondvar {
     inner: sys::CONDVAR_INIT,
diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs
index 4829be569cc..4d2fbfc4055 100644
--- a/src/libstd/sync/mutex.rs
+++ b/src/libstd/sync/mutex.rs
@@ -73,6 +73,10 @@ pub struct Mutex<T> {
     data: UnsafeCell<T>,
 }
 
+unsafe impl<T:Send> Send for Mutex<T> { }
+
+unsafe impl<T:Send> Sync for Mutex<T> { }
+
 /// The static mutex type is provided to allow for static allocation of mutexes.
 ///
 /// Note that this is a separate type because using a Mutex correctly means that
@@ -99,6 +103,8 @@ pub struct StaticMutex {
     poison: UnsafeCell<poison::Flag>,
 }
 
+unsafe impl Sync for StaticMutex {}
+
 /// An RAII implementation of a "scoped lock" of a mutex. When this structure is
 /// dropped (falls out of scope), the lock will be unlocked.
 ///
@@ -278,6 +284,11 @@ mod test {
     use thread::Thread;
     use sync::{Arc, Mutex, StaticMutex, MUTEX_INIT, Condvar};
 
+    struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
+
+    unsafe impl<T:'static+Send> Send for Packet<T> {}
+    unsafe impl<T> Sync for Packet<T> {}
+
     #[test]
     fn smoke() {
         let m = Mutex::new(());
@@ -337,19 +348,19 @@ mod test {
 
     #[test]
     fn test_mutex_arc_condvar() {
-        let arc = Arc::new((Mutex::new(false), Condvar::new()));
-        let arc2 = arc.clone();
+        let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
+        let packet2 = Packet(packet.0.clone());
         let (tx, rx) = channel();
         spawn(move|| {
             // wait until parent gets in
             rx.recv();
-            let &(ref lock, ref cvar) = &*arc2;
+            let &(ref lock, ref cvar) = &*packet2.0;
             let mut lock = lock.lock();
             *lock = true;
             cvar.notify_one();
         });
 
-        let &(ref lock, ref cvar) = &*arc;
+        let &(ref lock, ref cvar) = &*packet.0;
         let lock = lock.lock();
         tx.send(());
         assert!(!*lock);
@@ -361,20 +372,20 @@ mod test {
     #[test]
     #[should_fail]
     fn test_arc_condvar_poison() {
-        let arc = Arc::new((Mutex::new(1i), Condvar::new()));
-        let arc2 = arc.clone();
+        let packet = Packet(Arc::new((Mutex::new(1i), Condvar::new())));
+        let packet2 = Packet(packet.0.clone());
         let (tx, rx) = channel();
 
         spawn(move|| {
             rx.recv();
-            let &(ref lock, ref cvar) = &*arc2;
+            let &(ref lock, ref cvar) = &*packet2.0;
             let _g = lock.lock();
             cvar.notify_one();
             // Parent should fail when it wakes up.
             panic!();
         });
 
-        let &(ref lock, ref cvar) = &*arc;
+        let &(ref lock, ref cvar) = &*packet.0;
         let lock = lock.lock();
         tx.send(());
         while *lock == 1 {
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index a43f822e351..4d9fbb59908 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -14,6 +14,7 @@
 //! example use case would be for initializing an FFI library.
 
 use int;
+use kinds::Sync;
 use mem::drop;
 use ops::FnOnce;
 use sync::atomic;
@@ -41,6 +42,8 @@ pub struct Once {
     lock_cnt: atomic::AtomicInt,
 }
 
+unsafe impl Sync for Once {}
+
 /// Initialization value for static `Once` values.
 pub const ONCE_INIT: Once = Once {
     mutex: MUTEX_INIT,
diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs
index 3f177a42f44..76d05d9bfd4 100644
--- a/src/libstd/sync/rwlock.rs
+++ b/src/libstd/sync/rwlock.rs
@@ -60,6 +60,9 @@ pub struct RWLock<T> {
     data: UnsafeCell<T>,
 }
 
+unsafe impl<T:'static+Send> Send for RWLock<T> {}
+unsafe impl<T> Sync for RWLock<T> {}
+
 /// Structure representing a statically allocated RWLock.
 ///
 /// This structure is intended to be used inside of a `static` and will provide
@@ -88,6 +91,9 @@ pub struct StaticRWLock {
     poison: UnsafeCell<poison::Flag>,
 }
 
+unsafe impl Send for StaticRWLock {}
+unsafe impl Sync for StaticRWLock {}
+
 /// Constant initialization for a statically-initialized rwlock.
 pub const RWLOCK_INIT: StaticRWLock = StaticRWLock {
     inner: sys::RWLOCK_INIT,
diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs
index 421778e2012..a629f035b07 100644
--- a/src/libstd/sys/common/helper_thread.rs
+++ b/src/libstd/sys/common/helper_thread.rs
@@ -59,6 +59,15 @@ pub struct Helper<M> {
     pub shutdown: UnsafeCell<bool>,
 }
 
+unsafe impl<M:Send> Send for Helper<M> { }
+
+unsafe impl<M:Send> Sync for Helper<M> { }
+
+struct RaceBox(helper_signal::signal);
+
+unsafe impl Send for RaceBox {}
+unsafe impl Sync for RaceBox {}
+
 impl<M: Send> Helper<M> {
     /// Lazily boots a helper thread, becoming a no-op if the helper has already
     /// been spawned.
@@ -81,9 +90,11 @@ impl<M: Send> Helper<M> {
                 let (receive, send) = helper_signal::new();
                 *self.signal.get() = send as uint;
 
+                let receive = RaceBox(receive);
+
                 let t = f();
                 Thread::spawn(move |:| {
-                    helper(receive, rx, t);
+                    helper(receive.0, rx, t);
                     let _g = self.lock.lock();
                     *self.shutdown.get() = true;
                     self.cond.notify_one()
diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys/common/mutex.rs
index 1a8a92a105a..567c26956ef 100644
--- a/src/libstd/sys/common/mutex.rs
+++ b/src/libstd/sys/common/mutex.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use kinds::Sync;
 use sys::mutex as imp;
 
 /// An OS-based mutual exclusion lock.
@@ -17,6 +18,8 @@ use sys::mutex as imp;
 /// at the top level of the crate instead of this type.
 pub struct Mutex(imp::Mutex);
 
+unsafe impl Sync for Mutex {}
+
 /// Constant initializer for statically allocated mutexes.
 pub const MUTEX_INIT: Mutex = Mutex(imp::MUTEX_INIT);
 
diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs
index e76f2a2b872..a4ebcbd25d0 100644
--- a/src/libstd/sys/unix/c.rs
+++ b/src/libstd/sys/unix/c.rs
@@ -162,6 +162,9 @@ mod signal {
         sa_restorer: *mut libc::c_void,
     }
 
+    unsafe impl ::kinds::Send for sigaction { }
+    unsafe impl ::kinds::Sync for sigaction { }
+
     #[repr(C)]
     #[cfg(target_word_size = "32")]
     pub struct sigset_t {
@@ -211,6 +214,9 @@ mod signal {
         sa_resv: [libc::c_int, ..1],
     }
 
+    impl ::kinds::Send for sigaction { }
+    impl ::kinds::Sync for sigaction { }
+
     #[repr(C)]
     pub struct sigset_t {
         __val: [libc::c_ulong, ..32],
diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs
index 2f01c53cb2c..81f8659d6ae 100644
--- a/src/libstd/sys/unix/mutex.rs
+++ b/src/libstd/sys/unix/mutex.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use cell::UnsafeCell;
+use kinds::Sync;
 use sys::sync as ffi;
 use sys_common::mutex;
 
@@ -23,6 +24,8 @@ pub const MUTEX_INIT: Mutex = Mutex {
     inner: UnsafeCell { value: ffi::PTHREAD_MUTEX_INITIALIZER },
 };
 
+unsafe impl Sync for Mutex {}
+
 impl Mutex {
     #[inline]
     pub unsafe fn new() -> Mutex {
diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
index 348b7cfad33..f1b078b4e80 100644
--- a/src/libstd/sys/unix/pipe.rs
+++ b/src/libstd/sys/unix/pipe.rs
@@ -117,6 +117,9 @@ pub struct UnixStream {
     write_deadline: u64,
 }
 
+unsafe impl Send for UnixStream {}
+unsafe impl Sync for UnixStream {}
+
 impl UnixStream {
     pub fn connect(addr: &CString,
                    timeout: Option<u64>) -> IoResult<UnixStream> {
@@ -215,6 +218,9 @@ pub struct UnixListener {
     path: CString,
 }
 
+unsafe impl Send for UnixListener {}
+unsafe impl Sync for UnixListener {}
+
 impl UnixListener {
     pub fn bind(addr: &CString) -> IoResult<UnixListener> {
         bind(addr, libc::SOCK_STREAM).map(|fd| {
@@ -259,6 +265,9 @@ struct AcceptorInner {
     closed: atomic::AtomicBool,
 }
 
+unsafe impl Send for AcceptorInner {}
+unsafe impl Sync for AcceptorInner {}
+
 impl UnixAcceptor {
     pub fn fd(&self) -> fd_t { self.inner.listener.fd() }
 
diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs
index 340f9514241..bcbbb8766b7 100644
--- a/src/libstd/sys/unix/stack_overflow.rs
+++ b/src/libstd/sys/unix/stack_overflow.rs
@@ -160,7 +160,7 @@ mod imp {
 
         pub static SIGSTKSZ: libc::size_t = 8192;
 
-        pub static SIG_DFL: sighandler_t = 0i as sighandler_t;
+        pub const SIG_DFL: sighandler_t = 0i as sighandler_t;
 
         // This definition is not as accurate as it could be, {si_addr} is
         // actually a giant union. Currently we're only interested in that field,
diff --git a/src/libstd/sys/unix/tcp.rs b/src/libstd/sys/unix/tcp.rs
index 5c99ad1e0ce..e2a78947e16 100644
--- a/src/libstd/sys/unix/tcp.rs
+++ b/src/libstd/sys/unix/tcp.rs
@@ -33,6 +33,8 @@ pub struct TcpListener {
     pub inner: FileDesc,
 }
 
+unsafe impl Sync for TcpListener {}
+
 impl TcpListener {
     pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> {
         let fd = try!(net::socket(addr, libc::SOCK_STREAM));
@@ -96,6 +98,8 @@ struct AcceptorInner {
     closed: atomic::AtomicBool,
 }
 
+unsafe impl Sync for AcceptorInner {}
+
 impl TcpAcceptor {
     pub fn fd(&self) -> sock_t { self.inner.listener.fd() }
 
diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs
index ddd89070ed5..3ac7c09154e 100644
--- a/src/libstd/sys/windows/mutex.rs
+++ b/src/libstd/sys/windows/mutex.rs
@@ -22,6 +22,8 @@ pub struct Mutex { inner: atomic::AtomicUint }
 
 pub const MUTEX_INIT: Mutex = Mutex { inner: atomic::INIT_ATOMIC_UINT };
 
+unsafe impl Sync for Mutex {}
+
 #[inline]
 pub unsafe fn raw(m: &Mutex) -> ffi::LPCRITICAL_SECTION {
     m.get()
diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs
index bf658d0efd0..fc3640f2604 100644
--- a/src/libstd/sys/windows/pipe.rs
+++ b/src/libstd/sys/windows/pipe.rs
@@ -214,6 +214,9 @@ pub struct UnixStream {
     write_deadline: u64,
 }
 
+unsafe impl Send for UnixStream {}
+unsafe impl Sync for UnixStream {}
+
 impl UnixStream {
     fn try_connect(p: *const u16) -> Option<libc::HANDLE> {
         // Note that most of this is lifted from the libuv implementation.
@@ -559,6 +562,9 @@ pub struct UnixListener {
     name: CString,
 }
 
+unsafe impl Send for UnixListener {}
+unsafe impl Sync for UnixListener {}
+
 impl UnixListener {
     pub fn bind(addr: &CString) -> IoResult<UnixListener> {
         // Although we technically don't need the pipe until much later, we
@@ -603,11 +609,17 @@ pub struct UnixAcceptor {
     deadline: u64,
 }
 
+unsafe impl Send for UnixAcceptor {}
+unsafe impl Sync for UnixAcceptor {}
+
 struct AcceptorState {
     abort: Event,
     closed: atomic::AtomicBool,
 }
 
+unsafe impl Send for AcceptorState {}
+unsafe impl Sync for AcceptorState {}
+
 impl UnixAcceptor {
     pub fn accept(&mut self) -> IoResult<UnixStream> {
         // This function has some funky implementation details when working with
diff --git a/src/libstd/sys/windows/tcp.rs b/src/libstd/sys/windows/tcp.rs
index 505e6137bf9..513c1d38e36 100644
--- a/src/libstd/sys/windows/tcp.rs
+++ b/src/libstd/sys/windows/tcp.rs
@@ -24,6 +24,9 @@ pub use sys_common::net::TcpStream;
 
 pub struct Event(c::WSAEVENT);
 
+unsafe impl Send for Event {}
+unsafe impl Sync for Event {}
+
 impl Event {
     pub fn new() -> IoResult<Event> {
         let event = unsafe { c::WSACreateEvent() };
@@ -49,6 +52,9 @@ impl Drop for Event {
 
 pub struct TcpListener { sock: sock_t }
 
+unsafe impl Send for TcpListener {}
+unsafe impl Sync for TcpListener {}
+
 impl TcpListener {
     pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> {
         sys::init_net();
@@ -109,6 +115,9 @@ pub struct TcpAcceptor {
     deadline: u64,
 }
 
+unsafe impl Send for TcpAcceptor {}
+unsafe impl Sync for TcpAcceptor {}
+
 struct AcceptorInner {
     listener: TcpListener,
     abort: Event,
@@ -116,6 +125,9 @@ struct AcceptorInner {
     closed: atomic::AtomicBool,
 }
 
+unsafe impl Send for AcceptorInner {}
+unsafe impl Sync for AcceptorInner {}
+
 impl TcpAcceptor {
     pub fn socket(&self) -> sock_t { self.inner.listener.socket() }
 
diff --git a/src/libstd/sys/windows/timer.rs b/src/libstd/sys/windows/timer.rs
index 7e4dd768aa9..874838950cd 100644
--- a/src/libstd/sys/windows/timer.rs
+++ b/src/libstd/sys/windows/timer.rs
@@ -48,6 +48,9 @@ pub enum Req {
     RemoveTimer(libc::HANDLE, Sender<()>),
 }
 
+unsafe impl Send for Req {}
+
+
 fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) {
     let mut objs = vec![input];
     let mut chans = vec![];
diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs
index 89773207347..56731bd7ec3 100644
--- a/src/libstd/thread.rs
+++ b/src/libstd/thread.rs
@@ -129,7 +129,7 @@ use borrow::IntoCow;
 use boxed::Box;
 use cell::UnsafeCell;
 use clone::Clone;
-use kinds::Send;
+use kinds::{Send, Sync};
 use ops::{Drop, FnOnce};
 use option::Option::{mod, Some, None};
 use result::Result::{Err, Ok};
@@ -211,8 +211,8 @@ impl Builder {
     }
 
     fn spawn_inner<T: Send>(self, f: Thunk<(), T>) -> JoinGuard<T> {
-        let my_packet = Arc::new(UnsafeCell::new(None));
-        let their_packet = my_packet.clone();
+        let my_packet = Packet(Arc::new(UnsafeCell::new(None)));
+        let their_packet = Packet(my_packet.0.clone());
 
         let Builder { name, stack_size, stdout, stderr } = self;
 
@@ -266,7 +266,7 @@ impl Builder {
                 }
             };
             unsafe {
-                *their_packet.get() = Some(match (output, try_result) {
+                *their_packet.0.get() = Some(match (output, try_result) {
                     (Some(data), Ok(_)) => Ok(data),
                     (None, Err(cause)) => Err(cause),
                     _ => unreachable!()
@@ -289,12 +289,16 @@ struct Inner {
     cvar: Condvar,
 }
 
+unsafe impl Sync for Inner {}
+
 #[deriving(Clone)]
 /// A handle to a thread.
 pub struct Thread {
     inner: Arc<Inner>,
 }
 
+unsafe impl Sync for Thread {}
+
 impl Thread {
     // Used only internally to construct a thread object without spawning
     fn new(name: Option<String>) -> Thread {
@@ -379,6 +383,11 @@ impl thread_info::NewThread for Thread {
 /// A thread that completes without panicking is considered to exit successfully.
 pub type Result<T> = ::result::Result<T, Box<Any + Send>>;
 
+struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>);
+
+unsafe impl<T:'static+Send> Send for Packet<T> {}
+unsafe impl<T> Sync for Packet<T> {}
+
 #[must_use]
 /// An RAII-style guard that will block until thread termination when dropped.
 ///
@@ -387,9 +396,11 @@ pub struct JoinGuard<T> {
     native: imp::rust_thread,
     thread: Thread,
     joined: bool,
-    packet: Arc<UnsafeCell<Option<Result<T>>>>,
+    packet: Packet<T>,
 }
 
+unsafe impl<T: Send> Sync for JoinGuard<T> {}
+
 impl<T: Send> JoinGuard<T> {
     /// Extract a handle to the thread this guard will join on.
     pub fn thread(&self) -> &Thread {
@@ -406,7 +417,7 @@ impl<T: Send> JoinGuard<T> {
         unsafe { imp::join(self.native) };
         self.joined = true;
         unsafe {
-            (*self.packet.get()).take().unwrap()
+            (*self.packet.0.get()).take().unwrap()
         }
     }
 
diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs
index 04718dcc6ae..242dceb4256 100644
--- a/src/libstd/thread_local/mod.rs
+++ b/src/libstd/thread_local/mod.rs
@@ -280,6 +280,8 @@ mod imp {
         pub dtor_running: UnsafeCell<bool>, // should be Cell
     }
 
+    unsafe impl<T> ::kinds::Sync for Key<T> { }
+
     #[doc(hidden)]
     impl<T> Key<T> {
         pub unsafe fn get(&'static self) -> Option<&'static T> {
@@ -410,6 +412,8 @@ mod imp {
         pub os: OsStaticKey,
     }
 
+    unsafe impl<T> ::kinds::Sync for Key<T> { }
+
     struct Value<T: 'static> {
         key: &'static Key<T>,
         value: T,
diff --git a/src/libstd/thread_local/scoped.rs b/src/libstd/thread_local/scoped.rs
index 643a0f55e74..756c86c2115 100644
--- a/src/libstd/thread_local/scoped.rs
+++ b/src/libstd/thread_local/scoped.rs
@@ -198,10 +198,11 @@ impl<T> Key<T> {
 mod imp {
     use std::cell::UnsafeCell;
 
-    // FIXME: Should be a `Cell`, but that's not `Sync`
     #[doc(hidden)]
     pub struct KeyInner<T> { pub inner: UnsafeCell<*mut T> }
 
+    unsafe impl<T> ::kinds::Sync for KeyInner<T> { }
+
     #[doc(hidden)]
     impl<T> KeyInner<T> {
         #[doc(hidden)]
@@ -222,6 +223,8 @@ mod imp {
         pub marker: marker::InvariantType<T>,
     }
 
+    unsafe impl<T> ::kinds::Sync for KeyInner<T> { }
+
     #[doc(hidden)]
     impl<T> KeyInner<T> {
         #[doc(hidden)]
diff --git a/src/libsyntax/ext/deriving/bounds.rs b/src/libsyntax/ext/deriving/bounds.rs
index c27a27fce6a..cf29bb048d6 100644
--- a/src/libsyntax/ext/deriving/bounds.rs
+++ b/src/libsyntax/ext/deriving/bounds.rs
@@ -26,8 +26,11 @@ pub fn expand_deriving_bound<F>(cx: &mut ExtCtxt,
         MetaWord(ref tname) => {
             match tname.get() {
                 "Copy" => "Copy",
-                "Send" => "Send",
-                "Sync" => "Sync",
+                "Send" | "Sync" => {
+                    return cx.span_err(span,
+                                       format!("{} is an unsafe trait and it \
+                                               should be implemented explicitly", *tname)[])
+                }
                 ref tname => {
                     cx.span_bug(span,
                                 format!("expected built-in trait name but \
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 4b73fe04c85..88dd6fce88f 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -976,6 +976,8 @@ enum TestEvent {
 
 pub type MonitorMsg = (TestDesc, TestResult, Vec<u8> );
 
+unsafe impl Send for MonitorMsg {}
+
 fn run_tests<F>(opts: &TestOpts,
                 tests: Vec<TestDescAndFn> ,
                 mut callback: F) -> io::IoResult<()> where
diff --git a/src/test/bench/shootout-reverse-complement.rs b/src/test/bench/shootout-reverse-complement.rs
index d746ec1dbab..66965110f73 100644
--- a/src/test/bench/shootout-reverse-complement.rs
+++ b/src/test/bench/shootout-reverse-complement.rs
@@ -46,7 +46,7 @@ extern crate libc;
 
 use std::io::stdio::{stdin_raw, stdout_raw};
 use std::num::{div_rem};
-use std::ptr::{copy_memory};
+use std::ptr::{copy_memory, Unique};
 use std::io::{IoResult, EndOfFile};
 
 struct Tables {
@@ -219,10 +219,15 @@ fn reverse_complement(seq: &mut [u8], tables: &Tables) {
     }
 }
 
+
+struct Racy<T>(T);
+
+unsafe impl<T: 'static> Send for Racy<T> {}
+
 /// Executes a closure in parallel over the given iterator over mutable slice.
 /// The closure `f` is run in parallel with an element of `iter`.
 fn parallel<'a, I, T, F>(mut iter: I, f: F)
-        where T: Send + Sync,
+        where T: 'a+Send + Sync,
               I: Iterator<&'a mut [T]>,
               F: Fn(&'a mut [T]) + Sync {
     use std::mem;
@@ -234,11 +239,11 @@ fn parallel<'a, I, T, F>(mut iter: I, f: F)
 
         // Need to convert `f` and `chunk` to something that can cross the task
         // boundary.
-        let f = &f as *const F as *const uint;
-        let raw = chunk.repr();
+        let f = Racy(&f as *const F as *const uint);
+        let raw = Racy(chunk.repr());
         spawn(move|| {
-            let f = f as *const F;
-            unsafe { (*f)(mem::transmute(raw)) }
+            let f = f.0 as *const F;
+            unsafe { (*f)(mem::transmute(raw.0)) }
             drop(tx)
         });
     }
diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs
index 647c47b00a0..df388fbdde5 100644
--- a/src/test/bench/shootout-spectralnorm.rs
+++ b/src/test/bench/shootout-spectralnorm.rs
@@ -108,6 +108,11 @@ fn dot(v: &[f64], u: &[f64]) -> f64 {
     v.iter().zip(u.iter()).map(|(a, b)| *a * *b).sum()
 }
 
+
+struct Racy<T>(T);
+
+unsafe impl<T: 'static> Send for Racy<T> {}
+
 // Executes a closure in parallel over the given mutable slice. The closure `f`
 // is run in parallel and yielded the starting index within `v` as well as a
 // sub-slice of `v`.
@@ -122,11 +127,11 @@ fn parallel<'a, T, F>(v: &'a mut [T], f: F)
 
         // Need to convert `f` and `chunk` to something that can cross the task
         // boundary.
-        let f = &f as *const _ as *const uint;
-        let raw = chunk.repr();
+        let f = Racy(&f as *const _ as *const uint);
+        let raw = Racy(chunk.repr());
         spawn(move|| {
-            let f = f as *const F;
-            unsafe { (*f)(i * size, mem::transmute(raw)) }
+            let f = f.0 as *const F;
+            unsafe { (*f)(i * size, mem::transmute(raw.0)) }
             drop(tx)
         });
     }
diff --git a/src/test/compile-fail/deriving-bounds.rs b/src/test/compile-fail/deriving-bounds.rs
index 1f9bd881afe..d61ad98ee1e 100644
--- a/src/test/compile-fail/deriving-bounds.rs
+++ b/src/test/compile-fail/deriving-bounds.rs
@@ -8,8 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[deriving(Sync(Bad),Send,Copy)]
+#[deriving(Copy(Bad))]
 //~^ ERROR unexpected value in deriving, expected a trait
 struct Test;
 
+#[deriving(Sync)]
+//~^ ERROR Sync is an unsafe trait and it should be implemented explicitly
+struct Test1;
+
 pub fn main() {}
diff --git a/src/test/compile-fail/issue-17718-static-sync.rs b/src/test/compile-fail/issue-17718-static-sync.rs
index 2304b18adb6..63a40e2374b 100644
--- a/src/test/compile-fail/issue-17718-static-sync.rs
+++ b/src/test/compile-fail/issue-17718-static-sync.rs
@@ -14,6 +14,6 @@ struct Foo { marker: marker::NoSync }
 
 static FOO: uint = 3;
 static BAR: Foo = Foo { marker: marker::NoSync };
-//~^ ERROR: shared static items must have a type which implements Sync
+//~^ ERROR: the trait `core::kinds::Sync` is not implemented
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs
index bef8ca6b86c..a8a699d62d5 100644
--- a/src/test/compile-fail/issue-7013.rs
+++ b/src/test/compile-fail/issue-7013.rs
@@ -33,4 +33,5 @@ struct A {
 fn main() {
     let a = A {v: box B{v: None} as Box<Foo+Send>};
     //~^ ERROR the trait `core::kinds::Send` is not implemented
+    //~^^ ERROR the trait `core::kinds::Send` is not implemented
 }
diff --git a/src/test/compile-fail/issue-7364.rs b/src/test/compile-fail/issue-7364.rs
index 7f0d9ef3b11..2646edd7684 100644
--- a/src/test/compile-fail/issue-7364.rs
+++ b/src/test/compile-fail/issue-7364.rs
@@ -14,6 +14,8 @@ use std::cell::RefCell;
 // Regresion test for issue 7364
 static boxed: Box<RefCell<int>> = box RefCell::new(0);
 //~^ ERROR statics are not allowed to have custom pointers
-//~^^ ERROR: shared static items must have a type which implements Sync
+//~^^ ERROR: the trait `core::kinds::Sync` is not implemented for the type
+//~^^^ ERROR: the trait `core::kinds::Sync` is not implemented for the type
+//~^^^^ ERROR: the trait `core::kinds::Sync` is not implemented for the type
 
 fn main() { }
diff --git a/src/test/compile-fail/kindck-destructor-owned.rs b/src/test/compile-fail/kindck-destructor-owned.rs
index 1a82a2b3832..803da617abd 100644
--- a/src/test/compile-fail/kindck-destructor-owned.rs
+++ b/src/test/compile-fail/kindck-destructor-owned.rs
@@ -9,19 +9,6 @@
 // except according to those terms.
 
 
-use std::rc::Rc;
-
-struct Foo {
-    f: Rc<int>,
-}
-
-impl Drop for Foo {
-//~^ ERROR the trait `core::kinds::Send` is not implemented
-//~^^ NOTE cannot implement a destructor on a structure or enumeration that does not satisfy Send
-    fn drop(&mut self) {
-    }
-}
-
 struct Bar<'a> {
     f: &'a int,
 }
diff --git a/src/test/compile-fail/kindck-nonsendable-1.rs b/src/test/compile-fail/kindck-nonsendable-1.rs
index c96054afc2f..fdd8584a8bb 100644
--- a/src/test/compile-fail/kindck-nonsendable-1.rs
+++ b/src/test/compile-fail/kindck-nonsendable-1.rs
@@ -17,6 +17,8 @@ fn bar<F:FnOnce() + Send>(_: F) { }
 
 fn main() {
     let x = Rc::new(3u);
-    bar(move|| foo(x)); //~ ERROR `core::kinds::Send` is not implemented
+    bar(move|| foo(x));
+    //~^ ERROR `core::kinds::Send` is not implemented
+    //~^^ ERROR `core::kinds::Send` is not implemented
 }
 
diff --git a/src/test/compile-fail/kindck-send-unsafe.rs b/src/test/compile-fail/kindck-send-unsafe.rs
index 33314149d1f..4e1641025d5 100644
--- a/src/test/compile-fail/kindck-send-unsafe.rs
+++ b/src/test/compile-fail/kindck-send-unsafe.rs
@@ -8,14 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+extern crate core;
+
 fn assert_send<T:Send>() { }
 
-// unsafe ptrs are ok unless they point at unsendable things
-fn test70() {
-    assert_send::<*mut int>();
-}
 fn test71<'a>() {
-    assert_send::<*mut &'a int>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<*mut &'a int>();
+    //~^ ERROR the trait `core::kinds::Send` is not implemented for the type
 }
 
 fn main() {
diff --git a/src/test/compile-fail/mut-not-freeze.rs b/src/test/compile-fail/mut-not-freeze.rs
index 60921c04135..4b058f6fdb3 100644
--- a/src/test/compile-fail/mut-not-freeze.rs
+++ b/src/test/compile-fail/mut-not-freeze.rs
@@ -14,5 +14,8 @@ fn f<T: Sync>(_: T) {}
 
 fn main() {
     let x = RefCell::new(0i);
-    f(x); //~ ERROR `core::kinds::Sync` is not implemented
+    f(x);
+    //~^ ERROR `core::kinds::Sync` is not implemented
+    //~^^ ERROR `core::kinds::Sync` is not implemented
+    //~^^^ ERROR `core::kinds::Sync` is not implemented
 }
diff --git a/src/test/compile-fail/no-send-res-ports.rs b/src/test/compile-fail/no-send-res-ports.rs
index e1ba36de7c0..48747c7ce1d 100644
--- a/src/test/compile-fail/no-send-res-ports.rs
+++ b/src/test/compile-fail/no-send-res-ports.rs
@@ -37,6 +37,7 @@ fn main() {
 
     task::spawn(move|| {
         //~^ ERROR `core::kinds::Send` is not implemented
+        //~^^ ERROR `core::kinds::Send` is not implemented
         let y = x;
         println!("{}", y);
     });
diff --git a/src/test/compile-fail/no_send-rc.rs b/src/test/compile-fail/no_send-rc.rs
index c05b17afe1d..004921b1db0 100644
--- a/src/test/compile-fail/no_send-rc.rs
+++ b/src/test/compile-fail/no_send-rc.rs
@@ -16,4 +16,5 @@ fn main() {
     let x = Rc::new(5i);
     bar(x);
     //~^ ERROR `core::kinds::Send` is not implemented
+    //~^^ ERROR `core::kinds::Send` is not implemented
 }
diff --git a/src/test/compile-fail/no_share-rc.rs b/src/test/compile-fail/no_share-rc.rs
index 5572f72d8fe..ac3b456def5 100644
--- a/src/test/compile-fail/no_share-rc.rs
+++ b/src/test/compile-fail/no_share-rc.rs
@@ -17,4 +17,5 @@ fn main() {
     let x = Rc::new(RefCell::new(5i));
     bar(x);
     //~^ ERROR the trait `core::kinds::Sync` is not implemented
+    //~^^ ERROR the trait `core::kinds::Sync` is not implemented
 }
diff --git a/src/test/compile-fail/regions-bounded-by-send.rs b/src/test/compile-fail/regions-bounded-by-send.rs
index 67655f323f0..e15cb25295a 100644
--- a/src/test/compile-fail/regions-bounded-by-send.rs
+++ b/src/test/compile-fail/regions-bounded-by-send.rs
@@ -12,8 +12,11 @@
 // in this file all test region bound and lifetime violations that are
 // detected during type check.
 
+extern crate core;
+use core::ptr::Unique;
+
 fn assert_send<T:Send>() { }
-trait Dummy { }
+trait Dummy:Send { }
 
 // lifetime pointers with 'static lifetime are ok
 
@@ -58,7 +61,7 @@ fn box_with_region_not_ok<'a>() {
 
 fn object_with_random_bound_not_ok<'a>() {
     assert_send::<&'a (Dummy+'a)>();
-    //~^ ERROR not implemented
+    //~^ ERROR reference has a longer lifetime
 }
 
 fn object_with_send_bound_not_ok<'a>() {
@@ -73,17 +76,12 @@ fn closure_with_lifetime_not_ok<'a>() {
 
 // unsafe pointers are ok unless they point at unsendable things
 
-fn unsafe_ok1<'a>(_: &'a int) {
-    assert_send::<*const int>();
-    assert_send::<*mut int>();
-}
+struct UniqueUnsafePtr(Unique<*const int>);
 
-fn unsafe_ok2<'a>(_: &'a int) {
-    assert_send::<*const &'a int>(); //~ ERROR declared lifetime bound not satisfied
-}
+unsafe impl Send for UniqueUnsafePtr {}
 
-fn unsafe_ok3<'a>(_: &'a int) {
-    assert_send::<*mut &'a int>(); //~ ERROR declared lifetime bound not satisfied
+fn unsafe_ok1<'a>(_: &'a int) {
+    assert_send::<UniqueUnsafePtr>();
 }
 
 fn main() {
diff --git a/src/test/compile-fail/task-rng-isnt-sendable.rs b/src/test/compile-fail/task-rng-isnt-sendable.rs
index e9997083bab..d96599404de 100644
--- a/src/test/compile-fail/task-rng-isnt-sendable.rs
+++ b/src/test/compile-fail/task-rng-isnt-sendable.rs
@@ -17,4 +17,5 @@ fn test_send<S: Send>() {}
 pub fn main() {
     test_send::<rand::TaskRng>();
     //~^ ERROR `core::kinds::Send` is not implemented
+    //~^^ ERROR `core::kinds::Send` is not implemented
 }
diff --git a/src/test/compile-fail/typeck-unsafe-always-share.rs b/src/test/compile-fail/typeck-unsafe-always-share.rs
index 7c74cdc890d..a7911eb791e 100644
--- a/src/test/compile-fail/typeck-unsafe-always-share.rs
+++ b/src/test/compile-fail/typeck-unsafe-always-share.rs
@@ -30,12 +30,15 @@ fn test<T: Sync>(s: T){
 fn main() {
     let us = UnsafeCell::new(MySync{u: UnsafeCell::new(0i)});
     test(us);
+    //~^ ERROR `core::kinds::Sync` is not implemented
 
     let uns = UnsafeCell::new(NoSync{m: marker::NoSync});
     test(uns);
+    //~^ ERROR `core::kinds::Sync` is not implemented
 
     let ms = MySync{u: uns};
     test(ms);
+    //~^ ERROR `core::kinds::Sync` is not implemented
 
     let ns = NoSync{m: marker::NoSync};
     test(ns);
diff --git a/src/test/compile-fail/unique-unique-kind.rs b/src/test/compile-fail/unique-unique-kind.rs
index 4c2805bf4bd..48d5028f435 100644
--- a/src/test/compile-fail/unique-unique-kind.rs
+++ b/src/test/compile-fail/unique-unique-kind.rs
@@ -16,5 +16,7 @@ fn f<T:Send>(_i: T) {
 
 fn main() {
     let i = box Rc::new(100i);
-    f(i); //~ ERROR `core::kinds::Send` is not implemented
+    f(i);
+    //~^ ERROR `core::kinds::Send` is not implemented
+    //~^^ ERROR `core::kinds::Send` is not implemented
 }
diff --git a/src/test/compile-fail/unsendable-class.rs b/src/test/compile-fail/unsendable-class.rs
index d988a245700..cd5918e2f47 100644
--- a/src/test/compile-fail/unsendable-class.rs
+++ b/src/test/compile-fail/unsendable-class.rs
@@ -28,6 +28,8 @@ fn foo(i:int, j: Rc<String>) -> foo {
 
 fn main() {
   let cat = "kitty".to_string();
-  let (tx, _) = channel(); //~ ERROR `core::kinds::Send` is not implemented
+  let (tx, _) = channel();
+  //~^ ERROR `core::kinds::Send` is not implemented
+  //~^^ ERROR `core::kinds::Send` is not implemented
   tx.send(foo(42, Rc::new(cat)));
 }
diff --git a/src/test/run-pass/const-block.rs b/src/test/run-pass/const-block.rs
index 01eccc53427..35783ea5899 100644
--- a/src/test/run-pass/const-block.rs
+++ b/src/test/run-pass/const-block.rs
@@ -11,11 +11,15 @@
 #![allow(dead_code)]
 #![allow(unused_unsafe)]
 
+use std::kinds::Sync;
+
 struct Foo {
     a: uint,
     b: *const ()
 }
 
+unsafe impl Sync for Foo {}
+
 fn foo<T>(a: T) -> T {
     a
 }
diff --git a/src/test/run-pass/const-cast-ptr-int.rs b/src/test/run-pass/const-cast-ptr-int.rs
index e4734fc3e55..50e460bd179 100644
--- a/src/test/run-pass/const-cast-ptr-int.rs
+++ b/src/test/run-pass/const-cast-ptr-int.rs
@@ -10,8 +10,14 @@
 
 use std::ptr;
 
-static a: *const u8 = 0 as *const u8;
+struct TestStruct {
+    x: *const u8
+}
+
+unsafe impl Sync for TestStruct {}
+
+static a: TestStruct = TestStruct{x: 0 as *const u8};
 
 pub fn main() {
-    assert_eq!(a, ptr::null());
+    assert_eq!(a.x, ptr::null());
 }
diff --git a/src/test/run-pass/const-cast.rs b/src/test/run-pass/const-cast.rs
index 5d8e31f9344..b7e9c0338dd 100644
--- a/src/test/run-pass/const-cast.rs
+++ b/src/test/run-pass/const-cast.rs
@@ -10,14 +10,16 @@
 
 extern crate libc;
 
-extern fn foo() {}
+struct TestStruct {
+    x: *const libc::c_void
+}
 
+unsafe impl Sync for TestStruct {}
+
+extern fn foo() {}
 const x: extern "C" fn() = foo;
-static y: *const libc::c_void = x as *const libc::c_void;
-const a: &'static int = &10;
-static b: *const int = a as *const int;
+static y: TestStruct = TestStruct { x: x as *const libc::c_void };
 
 pub fn main() {
-    assert_eq!(x as *const libc::c_void, y);
-    assert_eq!(a as *const int, b);
+    assert_eq!(x as *const libc::c_void, y.x);
 }
diff --git a/src/test/run-pass/deriving-bounds.rs b/src/test/run-pass/deriving-bounds.rs
index d120b8030c1..0bf27cfbb24 100644
--- a/src/test/run-pass/deriving-bounds.rs
+++ b/src/test/run-pass/deriving-bounds.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[deriving(Sync,Send,Copy)]
+#[deriving(Copy)]
 struct Test;
 
 pub fn main() {}
diff --git a/src/test/run-pass/issue-13837.rs b/src/test/run-pass/issue-13837.rs
index f62a45277b2..c6847ce55de 100644
--- a/src/test/run-pass/issue-13837.rs
+++ b/src/test/run-pass/issue-13837.rs
@@ -8,6 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-static TEST_VALUE : *const [int; 2] = 0x1234 as *const [int; 2];
+struct TestStruct {
+    x: *const [int; 2]
+}
+
+unsafe impl Sync for TestStruct {}
+
+static TEST_VALUE : TestStruct = TestStruct{x: 0x1234 as *const [int; 2]};
 
 fn main() {}
diff --git a/src/test/run-pass/issue-17718-static-unsafe-interior.rs b/src/test/run-pass/issue-17718-static-unsafe-interior.rs
index cd32857ede5..0851f0e367b 100644
--- a/src/test/run-pass/issue-17718-static-unsafe-interior.rs
+++ b/src/test/run-pass/issue-17718-static-unsafe-interior.rs
@@ -11,38 +11,46 @@
 use std::kinds::marker;
 use std::cell::UnsafeCell;
 
+struct MyUnsafePack<T>(UnsafeCell<T>);
+
+unsafe impl<T: Send> Sync for MyUnsafePack<T> {}
+
 struct MyUnsafe<T> {
-    value: UnsafeCell<T>
+    value: MyUnsafePack<T>
 }
 
 impl<T> MyUnsafe<T> {
     fn forbidden(&self) {}
 }
 
+unsafe impl<T: Send> Sync for MyUnsafe<T> {}
+
 enum UnsafeEnum<T> {
     VariantSafe,
     VariantUnsafe(UnsafeCell<T>)
 }
 
+unsafe impl<T: Send> Sync for UnsafeEnum<T> {}
+
 static STATIC1: UnsafeEnum<int> = UnsafeEnum::VariantSafe;
 
-static STATIC2: UnsafeCell<int> = UnsafeCell { value: 1 };
-const CONST: UnsafeCell<int> = UnsafeCell { value: 1 };
+static STATIC2: MyUnsafePack<int> = MyUnsafePack(UnsafeCell { value: 1 });
+const CONST: MyUnsafePack<int> = MyUnsafePack(UnsafeCell { value: 1 });
 static STATIC3: MyUnsafe<int> = MyUnsafe{value: CONST};
 
-static STATIC4: &'static UnsafeCell<int> = &STATIC2;
+static STATIC4: &'static MyUnsafePack<int> = &STATIC2;
 
 struct Wrap<T> {
     value: T
 }
 
-static UNSAFE: UnsafeCell<int> = UnsafeCell{value: 1};
-static WRAPPED_UNSAFE: Wrap<&'static UnsafeCell<int>> = Wrap { value: &UNSAFE };
+unsafe impl<T: Send> Sync for Wrap<T> {}
+
+static UNSAFE: MyUnsafePack<int> = MyUnsafePack(UnsafeCell{value: 2});
+static WRAPPED_UNSAFE: Wrap<&'static MyUnsafePack<int>> = Wrap { value: &UNSAFE };
 
 fn main() {
     let a = &STATIC1;
 
     STATIC3.forbidden()
 }
-
-
diff --git a/src/test/run-pass/issue-2718.rs b/src/test/run-pass/issue-2718.rs
index 3943d8a3f30..d949cab97c2 100644
--- a/src/test/run-pass/issue-2718.rs
+++ b/src/test/run-pass/issue-2718.rs
@@ -23,6 +23,7 @@ pub mod pipes {
     use std::mem::{replace, swap};
     use std::mem;
     use std::task;
+    use std::kinds::Send;
 
     pub struct Stuff<T> {
         state: state,
@@ -45,6 +46,8 @@ pub mod pipes {
         payload: Option<T>
     }
 
+    unsafe impl<T:Send> Send for packet<T> {}
+
     pub fn packet<T:Send>() -> *const packet<T> {
         unsafe {
             let p: *const packet<T> = mem::transmute(box Stuff{
@@ -230,8 +233,13 @@ pub mod pingpong {
     use std::mem;
 
     pub struct ping(::pipes::send_packet<pong>);
+
+    unsafe impl Send for ping {}
+
     pub struct pong(::pipes::send_packet<ping>);
 
+    unsafe impl Send for pong {}
+
     pub fn liberate_ping(p: ping) -> ::pipes::send_packet<pong> {
         unsafe {
             let _addr : *const ::pipes::send_packet<pong> = match &p {
diff --git a/src/test/run-pass/typeck_type_placeholder_1.rs b/src/test/run-pass/typeck_type_placeholder_1.rs
index 10c91274f10..a8ae3f40f0e 100644
--- a/src/test/run-pass/typeck_type_placeholder_1.rs
+++ b/src/test/run-pass/typeck_type_placeholder_1.rs
@@ -11,7 +11,14 @@
 // This test checks that the `_` type placeholder works
 // correctly for enabling type inference.
 
-static CONSTEXPR: *const int = &413 as *const _;
+struct TestStruct {
+    x: *const int
+}
+
+unsafe impl Sync for TestStruct {}
+
+static CONSTEXPR: TestStruct = TestStruct{x: &413 as *const _};
+
 
 pub fn main() {
     let x: Vec<_> = range(0u, 5).collect();