about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-11-06 11:51:09 -0800
committerbors <bors@rust-lang.org>2013-11-06 11:51:09 -0800
commitfdc830df31df205c8edc5e11268a011d44c8bc09 (patch)
treecb69b6802c38077ea53b53e03e62066738d94fc1 /src
parentdda67dfe27b261babd48a91b1eec1f5f32890d28 (diff)
parent71acc543ca0858a064c4bed848b507325c383939 (diff)
downloadrust-fdc830df31df205c8edc5e11268a011d44c8bc09.tar.gz
rust-fdc830df31df205c8edc5e11268a011d44c8bc09.zip
auto merge of #10289 : nikomatsakis/rust/issue-10157-TypeContents-refactor, r=pcwalton
See #10157. This compiles now.

Fixes #10278.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/trans/_match.rs4
-rw-r--r--src/librustc/middle/trans/base.rs2
-rw-r--r--src/librustc/middle/trans/closure.rs2
-rw-r--r--src/librustc/middle/trans/datum.rs2
-rw-r--r--src/librustc/middle/trans/debuginfo.rs4
-rw-r--r--src/librustc/middle/trans/glue.rs2
-rw-r--r--src/librustc/middle/trans/intrinsic.rs4
-rw-r--r--src/librustc/middle/trans/reflect.rs4
-rw-r--r--src/librustc/middle/trans/tvec.rs2
-rw-r--r--src/librustc/middle/trans/type_of.rs4
-rw-r--r--src/librustc/middle/trans/uniq.rs2
-rw-r--r--src/librustc/middle/ty.rs470
-rw-r--r--src/librustc/middle/typeck/check/mod.rs2
-rw-r--r--src/librustuv/uvio.rs19
-rw-r--r--src/libstd/unstable/intrinsics.rs5
-rw-r--r--src/libstd/vec.rs29
-rw-r--r--src/test/compile-fail/kindck-freeze.rs56
-rw-r--r--src/test/compile-fail/kindck-send.rs59
-rw-r--r--src/test/compile-fail/mutable-enum-indirect.rs12
19 files changed, 404 insertions, 280 deletions
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index a36d938052a..9bafea6d861 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -1600,7 +1600,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
         let pat_ty = node_id_type(bcx, pat_id);
         let llbox = Load(bcx, val);
         let unboxed = match ty::get(pat_ty).sty {
-            ty::ty_uniq(*) if !ty::type_contents(bcx.tcx(), pat_ty).contains_managed() => llbox,
+            ty::ty_uniq(*) if !ty::type_contents(bcx.tcx(), pat_ty).owns_managed() => llbox,
             _ => GEPi(bcx, llbox, [0u, abi::box_field_body])
         };
         compile_submatch(bcx, enter_uniq(bcx, dm, m, col, val),
@@ -2220,7 +2220,7 @@ fn bind_irrefutable_pat(bcx: @mut Block,
             let pat_ty = node_id_type(bcx, pat.id);
             let llbox = Load(bcx, val);
             let unboxed = match ty::get(pat_ty).sty {
-                ty::ty_uniq(*) if !ty::type_contents(bcx.tcx(), pat_ty).contains_managed() => llbox,
+                ty::ty_uniq(*) if !ty::type_contents(bcx.tcx(), pat_ty).owns_managed() => llbox,
                     _ => GEPi(bcx, llbox, [0u, abi::box_field_body])
             };
             bcx = bind_irrefutable_pat(bcx, inner, unboxed, binding_mode);
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 64a4c453b2d..37e4d4e82be 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -409,7 +409,7 @@ pub fn malloc_general(bcx: @mut Block, t: ty::t, heap: heap) -> MallocResult {
 }
 
 pub fn heap_for_unique(bcx: @mut Block, t: ty::t) -> heap {
-    if ty::type_contents(bcx.tcx(), t).contains_managed() {
+    if ty::type_contents(bcx.tcx(), t).owns_managed() {
         heap_managed_unique
     } else {
         heap_exchange
diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs
index f036f922de9..9629615c64d 100644
--- a/src/librustc/middle/trans/closure.rs
+++ b/src/librustc/middle/trans/closure.rs
@@ -156,7 +156,7 @@ pub fn mk_closure_tys(tcx: ty::ctxt,
 }
 
 fn heap_for_unique_closure(bcx: @mut Block, t: ty::t) -> heap {
-    if ty::type_contents(bcx.tcx(), t).contains_managed() {
+    if ty::type_contents(bcx.tcx(), t).owns_managed() {
         heap_managed_unique
     } else {
         heap_exchange_closure
diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs
index d57c24e37d5..1efa7f763d8 100644
--- a/src/librustc/middle/trans/datum.rs
+++ b/src/librustc/middle/trans/datum.rs
@@ -566,7 +566,7 @@ impl Datum {
             }
         };
 
-        if !header && !ty::type_contents(bcx.tcx(), content_ty).contains_managed() {
+        if !header && !ty::type_contents(bcx.tcx(), content_ty).owns_managed() {
             let ptr = self.to_value_llval(bcx);
             let ty = type_of::type_of(bcx.ccx(), content_ty);
             let body = PointerCast(bcx, ptr, ty.ptr_to());
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 3e17bc1b585..c6a33864620 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -2060,7 +2060,7 @@ fn type_metadata(cx: &mut CrateContext,
                 ty::vstore_fixed(len) => {
                     fixed_vec_metadata(cx, mt.ty, len, usage_site_span)
                 }
-                ty::vstore_uniq if ty::type_contents(cx.tcx, mt.ty).contains_managed() => {
+                ty::vstore_uniq if ty::type_contents(cx.tcx, mt.ty).owns_managed() => {
                     let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, usage_site_span);
                     pointer_type_metadata(cx, t, boxed_vec_metadata)
                 }
@@ -2077,7 +2077,7 @@ fn type_metadata(cx: &mut CrateContext,
                 }
             }
         },
-        ty::ty_uniq(ref mt) if ty::type_contents(cx.tcx, mt.ty).contains_managed() => {
+        ty::ty_uniq(ref mt) if ty::type_contents(cx.tcx, mt.ty).owns_managed() => {
             create_pointer_to_box_metadata(cx, t, mt.ty)
         },
         ty::ty_uniq(ref mt)    |
diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs
index 02b44907f33..f461120e4c3 100644
--- a/src/librustc/middle/trans/glue.rs
+++ b/src/librustc/middle/trans/glue.rs
@@ -603,7 +603,7 @@ pub fn declare_tydesc(ccx: &mut CrateContext, t: ty::t) -> @mut tydesc_info {
 
     let has_header = match ty::get(t).sty {
         ty::ty_box(*) => true,
-        ty::ty_uniq(*) => ty::type_contents(ccx.tcx, t).contains_managed(),
+        ty::ty_uniq(*) => ty::type_contents(ccx.tcx, t).owns_managed(),
         _ => false
     };
 
diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs
index 3d1c74028cc..a7af10b491e 100644
--- a/src/librustc/middle/trans/intrinsic.rs
+++ b/src/librustc/middle/trans/intrinsic.rs
@@ -387,9 +387,9 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
             let tp_ty = substs.tys[0];
             Ret(bcx, C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)));
         }
-        "contains_managed" => {
+        "owns_managed" => {
             let tp_ty = substs.tys[0];
-            Ret(bcx, C_bool(ty::type_contents(ccx.tcx, tp_ty).contains_managed()));
+            Ret(bcx, C_bool(ty::type_contents(ccx.tcx, tp_ty).owns_managed()));
         }
         "visit_tydesc" => {
             let td = get_param(decl, first_real_arg);
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index c56d8835549..2f4fcfed20b 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -183,7 +183,7 @@ impl Reflector {
           ty::ty_evec(ref mt, vst) => {
               let (name, extra) = self.vstore_name_and_extra(t, vst);
               let extra = extra + self.c_mt(mt);
-              if "uniq" == name && ty::type_contents(bcx.tcx(), t).contains_managed() {
+              if "uniq" == name && ty::type_contents(bcx.tcx(), t).owns_managed() {
                   self.visit("evec_uniq_managed", extra)
               } else {
                   self.visit(~"evec_" + name, extra)
@@ -195,7 +195,7 @@ impl Reflector {
           }
           ty::ty_uniq(ref mt) => {
               let extra = self.c_mt(mt);
-              if ty::type_contents(bcx.tcx(), t).contains_managed() {
+              if ty::type_contents(bcx.tcx(), t).owns_managed() {
                   self.visit("uniq_managed", extra)
               } else {
                   self.visit("uniq", extra)
diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs
index 1f9e9037179..93718fc1a23 100644
--- a/src/librustc/middle/trans/tvec.rs
+++ b/src/librustc/middle/trans/tvec.rs
@@ -65,7 +65,7 @@ pub fn get_alloc(bcx: @mut Block, vptr: ValueRef) -> ValueRef {
 }
 
 pub fn get_bodyptr(bcx: @mut Block, vptr: ValueRef, t: ty::t) -> ValueRef {
-    if ty::type_contents(bcx.tcx(), t).contains_managed() {
+    if ty::type_contents(bcx.tcx(), t).owns_managed() {
         GEPi(bcx, vptr, [0u, abi::box_field_body])
     } else {
         vptr
diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs
index 2a8d16a2ceb..604321a0492 100644
--- a/src/librustc/middle/trans/type_of.rs
+++ b/src/librustc/middle/trans/type_of.rs
@@ -226,7 +226,7 @@ pub fn type_of(cx: &mut CrateContext, t: ty::t) -> Type {
       ty::ty_opaque_box => Type::opaque_box(cx).ptr_to(),
       ty::ty_uniq(ref mt) => {
           let ty = type_of(cx, mt.ty);
-          if ty::type_contents(cx.tcx, mt.ty).contains_managed() {
+          if ty::type_contents(cx.tcx, mt.ty).owns_managed() {
               Type::unique(cx, &ty).ptr_to()
           } else {
               ty.ptr_to()
@@ -235,7 +235,7 @@ pub fn type_of(cx: &mut CrateContext, t: ty::t) -> Type {
       ty::ty_evec(ref mt, ty::vstore_uniq) => {
           let ty = type_of(cx, mt.ty);
           let ty = Type::vec(cx.sess.targ_cfg.arch, &ty);
-          if ty::type_contents(cx.tcx, mt.ty).contains_managed() {
+          if ty::type_contents(cx.tcx, mt.ty).owns_managed() {
               Type::unique(cx, &ty).ptr_to()
           } else {
               ty.ptr_to()
diff --git a/src/librustc/middle/trans/uniq.rs b/src/librustc/middle/trans/uniq.rs
index 93335de2292..8ff270e236f 100644
--- a/src/librustc/middle/trans/uniq.rs
+++ b/src/librustc/middle/trans/uniq.rs
@@ -27,7 +27,7 @@ pub fn make_free_glue(bcx: @mut Block, vptrptr: ValueRef, box_ty: ty::t)
         let body_datum = box_datum.box_body(bcx);
         let bcx = glue::drop_ty(bcx, body_datum.to_ref_llval(bcx),
                                 body_datum.ty);
-        if ty::type_contents(bcx.tcx(), box_ty).contains_managed() {
+        if ty::type_contents(bcx.tcx(), box_ty).owns_managed() {
             glue::trans_free(bcx, box_datum.val)
         } else {
             glue::trans_exchange_free(bcx, box_datum.val)
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 6c2fb2f095c..96bb2897e0e 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -1854,9 +1854,76 @@ fn type_needs_unwind_cleanup_(cx: ctxt, ty: t,
  * a type than to think about what is *not* contained within a type.
  */
 pub struct TypeContents {
-    bits: u32
+    bits: u64
 }
 
+macro_rules! def_type_content_sets(
+    (mod $mname:ident { $($name:ident = $bits:expr),+ }) => {
+        mod $mname {
+            use middle::ty::TypeContents;
+            $(pub static $name: TypeContents = TypeContents { bits: $bits };)+
+        }
+    }
+)
+
+def_type_content_sets!(
+    mod TC {
+        None                                = 0b0000__00000000__0000,
+
+        // Things that are interior to the value (first nibble):
+        InteriorUnsized                     = 0b0000__00000000__0001,
+        InteriorAll                         = 0b0000__00000000__1111,
+
+        // Things that are owned by the value (second and third nibbles):
+        OwnsOwned                           = 0b0000__00000001__0000,
+        OwnsDtor                            = 0b0000__00000010__0000,
+        OwnsManaged /* see [1] below */     = 0b0000__00000100__0000,
+        OwnsAffine                          = 0b0000__00001000__0000,
+        OwnsAll                             = 0b0000__11111111__0000,
+
+        // Things that are reachable by the value in any way (fourth nibble):
+        ReachesNonsendAnnot                 = 0b0001__00000000__0000,
+        ReachesBorrowed                     = 0b0010__00000000__0000,
+        ReachesManaged /* see [1] below */  = 0b0100__00000000__0000,
+        ReachesMutable                      = 0b1000__00000000__0000,
+        ReachesAll                          = 0b1111__00000000__0000,
+
+        // Things that cause values to *move* rather than *copy*
+        Moves                               = 0b0000__00001011__0000,
+
+        // Things that mean drop glue is necessary
+        NeedsDrop                           = 0b0000__00000111__0000,
+
+        // Things that prevent values from being sent
+        //
+        // Note: For checking whether something is sendable, it'd
+        //       be sufficient to have ReachesManaged. However, we include
+        //       both ReachesManaged and OwnsManaged so that when
+        //       a parameter has a bound T:Send, we are able to deduce
+        //       that it neither reaches nor owns a managed pointer.
+        Nonsendable                         = 0b0111__00000100__0000,
+
+        // Things that prevent values from being considered freezable
+        Nonfreezable                        = 0b1000__00000000__0000,
+
+        // Things that prevent values from being considered 'static
+        Nonstatic                           = 0b0010__00000000__0000,
+
+        // Things that prevent values from being considered sized
+        Nonsized                            = 0b0000__00000000__0001,
+
+        // Bits to set when a managed value is encountered
+        //
+        // [1] Do not set the bits TC::OwnsManaged or
+        //     TC::ReachesManaged directly, instead reference
+        //     TC::Managed to set them both at once.
+        Managed                             = 0b0100__00000100__0000,
+
+        // All bits
+        All                                 = 0b1111__11111111__1111
+    }
+)
+
 impl TypeContents {
     pub fn meets_bounds(&self, cx: ctxt, bbs: BuiltinBounds) -> bool {
         bbs.iter().all(|bb| self.meets_bound(cx, bb))
@@ -1871,81 +1938,78 @@ impl TypeContents {
         }
     }
 
-    pub fn intersects(&self, tc: TypeContents) -> bool {
-        (self.bits & tc.bits) != 0
-    }
-
-    pub fn noncopyable(_cx: ctxt) -> TypeContents {
-        TC_DTOR + TC_BORROWED_MUT + TC_ONCE_CLOSURE + TC_NONCOPY_TRAIT +
-            TC_EMPTY_ENUM
+    pub fn when(&self, cond: bool) -> TypeContents {
+        if cond {*self} else {TC::None}
     }
 
-    pub fn is_static(&self, cx: ctxt) -> bool {
-        !self.intersects(TypeContents::nonstatic(cx))
+    pub fn intersects(&self, tc: TypeContents) -> bool {
+        (self.bits & tc.bits) != 0
     }
 
-    pub fn nonstatic(_cx: ctxt) -> TypeContents {
-        TC_BORROWED_POINTER
+    pub fn is_static(&self, _: ctxt) -> bool {
+        !self.intersects(TC::Nonstatic)
     }
 
-    pub fn is_sendable(&self, cx: ctxt) -> bool {
-        !self.intersects(TypeContents::nonsendable(cx))
+    pub fn is_sendable(&self, _: ctxt) -> bool {
+        !self.intersects(TC::Nonsendable)
     }
 
-    pub fn nonsendable(_cx: ctxt) -> TypeContents {
-        TC_MANAGED + TC_BORROWED_POINTER + TC_NON_SENDABLE
+    pub fn owns_managed(&self) -> bool {
+        self.intersects(TC::OwnsManaged)
     }
 
-    pub fn contains_managed(&self) -> bool {
-        self.intersects(TC_MANAGED)
+    pub fn is_freezable(&self, _: ctxt) -> bool {
+        !self.intersects(TC::Nonfreezable)
     }
 
-    pub fn is_freezable(&self, cx: ctxt) -> bool {
-        !self.intersects(TypeContents::nonfreezable(cx))
+    pub fn is_sized(&self, _: ctxt) -> bool {
+        !self.intersects(TC::Nonsized)
     }
 
-    pub fn nonfreezable(_cx: ctxt) -> TypeContents {
-        TC_MUTABLE
+    pub fn moves_by_default(&self, _: ctxt) -> bool {
+        self.intersects(TC::Moves)
     }
 
-    pub fn is_sized(&self, cx: ctxt) -> bool {
-        !self.intersects(TypeContents::dynamically_sized(cx))
+    pub fn needs_drop(&self, _: ctxt) -> bool {
+        self.intersects(TC::NeedsDrop)
     }
 
-    pub fn dynamically_sized(_cx: ctxt) -> TypeContents {
-        TC_DYNAMIC_SIZE
+    pub fn owned_pointer(&self) -> TypeContents {
+        /*!
+         * Includes only those bits that still apply
+         * when indirected through a `~` pointer
+         */
+        TC::OwnsOwned | (
+            *self & (TC::OwnsAll | TC::ReachesAll))
     }
 
-    pub fn moves_by_default(&self, cx: ctxt) -> bool {
-        self.intersects(TypeContents::nonimplicitly_copyable(cx))
+    pub fn other_pointer(&self, bits: TypeContents) -> TypeContents {
+        /*!
+         * Includes only those bits that still apply
+         * when indirected through a non-owning pointer (`&`, `@`)
+         */
+        bits | (
+            *self & TC::ReachesAll)
     }
 
-    pub fn nonimplicitly_copyable(cx: ctxt) -> TypeContents {
-        TypeContents::noncopyable(cx) + TC_OWNED_POINTER + TC_OWNED_VEC
+    pub fn union<T>(v: &[T], f: &fn(&T) -> TypeContents) -> TypeContents {
+        v.iter().fold(TC::None, |tc, t| tc | f(t))
     }
 
-    pub fn needs_drop(&self, cx: ctxt) -> bool {
-        if self.intersects(TC_NONCOPY_TRAIT) {
-            // Currently all noncopyable existentials are 2nd-class types
-            // behind owned pointers. With dynamically-sized types, remove
-            // this assertion.
-            assert!(self.intersects(TC_OWNED_POINTER) ||
-                    // (...or stack closures without a copy bound.)
-                    self.intersects(TC_BORROWED_POINTER));
-        }
-        let tc = TC_MANAGED + TC_DTOR + TypeContents::sendable(cx);
-        self.intersects(tc)
+    pub fn inverse(&self) -> TypeContents {
+        TypeContents { bits: !self.bits }
     }
+}
 
-    pub fn sendable(_cx: ctxt) -> TypeContents {
-        //! Any kind of sendable contents.
-        TC_OWNED_POINTER + TC_OWNED_VEC
+impl ops::BitOr<TypeContents,TypeContents> for TypeContents {
+    fn bitor(&self, other: &TypeContents) -> TypeContents {
+        TypeContents {bits: self.bits | other.bits}
     }
 }
 
-impl ops::Add<TypeContents,TypeContents> for TypeContents {
-    fn add(&self, other: &TypeContents) -> TypeContents {
-        TypeContents {bits: self.bits | other.bits}
+impl ops::BitAnd<TypeContents,TypeContents> for TypeContents {
+    fn bitand(&self, other: &TypeContents) -> TypeContents {
+        TypeContents {bits: self.bits & other.bits}
     }
 }
 
@@ -1961,48 +2025,6 @@ impl ToStr for TypeContents {
     }
 }
 
-/// Constant for a type containing nothing of interest.
-static TC_NONE: TypeContents =             TypeContents{bits: 0b0000_0000_0000};
-
-/// Contains a borrowed value with a lifetime other than static
-static TC_BORROWED_POINTER: TypeContents = TypeContents{bits: 0b0000_0000_0001};
-
-/// Contains an owned pointer (~T) but not slice of some kind
-static TC_OWNED_POINTER: TypeContents =    TypeContents{bits: 0b0000_0000_0010};
-
-/// Contains an owned vector ~[] or owned string ~str
-static TC_OWNED_VEC: TypeContents =        TypeContents{bits: 0b0000_0000_0100};
-
-/// Contains a non-copyable ~fn() or a ~Trait (NOT a ~fn:Copy() or ~Trait:Copy).
-static TC_NONCOPY_TRAIT: TypeContents =    TypeContents{bits: 0b0000_0000_1000};
-
-/// Type with a destructor
-static TC_DTOR: TypeContents =             TypeContents{bits: 0b0000_0001_0000};
-
-/// Contains a managed value
-static TC_MANAGED: TypeContents =          TypeContents{bits: 0b0000_0010_0000};
-
-/// &mut with any region
-static TC_BORROWED_MUT: TypeContents =     TypeContents{bits: 0b0000_0100_0000};
-
-/// Mutable content, whether owned or by ref
-static TC_MUTABLE: TypeContents =          TypeContents{bits: 0b0000_1000_0000};
-
-/// One-shot closure
-static TC_ONCE_CLOSURE: TypeContents =     TypeContents{bits: 0b0001_0000_0000};
-
-/// An enum with no variants.
-static TC_EMPTY_ENUM: TypeContents =       TypeContents{bits: 0b0010_0000_0000};
-
-/// Contains a type marked with `#[no_send]`
-static TC_NON_SENDABLE: TypeContents =     TypeContents{bits: 0b0100_0000_0000};
-
-/// Is a bare vector, str, function, trait, etc (only relevant at top level).
-static TC_DYNAMIC_SIZE: TypeContents =     TypeContents{bits: 0b1000_0000_0000};
-
-/// All possible contents.
-static TC_ALL: TypeContents =              TypeContents{bits: 0b1111_1111_1111};
-
 pub fn type_is_static(cx: ctxt, t: ty::t) -> bool {
     type_contents(cx, t).is_static(cx)
 }
@@ -2039,19 +2061,19 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
         //
         // When computing the type contents of such a type, we wind up deeply
         // recursing as we go.  So when we encounter the recursive reference
-        // to List, we temporarily use TC_NONE as its contents.  Later we'll
+        // to List, we temporarily use TC::None as its contents.  Later we'll
         // patch up the cache with the correct value, once we've computed it
         // (this is basically a co-inductive process, if that helps).  So in
-        // the end we'll compute TC_OWNED_POINTER, in this case.
+        // the end we'll compute TC::OwnsOwned, in this case.
         //
         // The problem is, as we are doing the computation, we will also
         // compute an *intermediate* contents for, e.g., Option<List> of
-        // TC_NONE.  This is ok during the computation of List itself, but if
+        // TC::None.  This is ok during the computation of List itself, but if
         // we stored this intermediate value into cx.tc_cache, then later
-        // requests for the contents of Option<List> would also yield TC_NONE
+        // requests for the contents of Option<List> would also yield TC::None
         // which is incorrect.  This value was computed based on the crutch
         // value for the type contents of list.  The correct value is
-        // TC_OWNED_POINTER.  This manifested as issue #4821.
+        // TC::OwnsOwned.  This manifested as issue #4821.
         let ty_id = type_id(ty);
         match cache.find(&ty_id) {
             Some(tc) => { return *tc; }
@@ -2061,108 +2083,96 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
             Some(tc) => { return *tc; }
             None => {}
         }
-        cache.insert(ty_id, TC_NONE);
-
-        let _i = indenter();
+        cache.insert(ty_id, TC::None);
 
         let result = match get(ty).sty {
             // Scalar and unique types are sendable, freezable, and durable
-            ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
-            ty_bare_fn(_) | ty_ptr(_) => {
-                TC_NONE
+            ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
+            ty_bare_fn(_) | ty::ty_char => {
+                TC::None
             }
 
             ty_estr(vstore_uniq) => {
-                TC_OWNED_VEC
+                TC::OwnsOwned
             }
 
             ty_closure(ref c) => {
-                closure_contents(c)
+                closure_contents(cx, c)
             }
 
             ty_box(mt) => {
-                TC_MANAGED +
-                    statically_sized(nonsendable(tc_mt(cx, mt, cache)))
+                tc_mt(cx, mt, cache).other_pointer(TC::Managed)
             }
 
             ty_trait(_, _, store, mutbl, bounds) => {
-                trait_contents(store, mutbl, bounds)
+                object_contents(cx, store, mutbl, bounds)
             }
 
-            ty_rptr(r, mt) => {
-                borrowed_contents(r, mt.mutbl) +
-                    statically_sized(nonsendable(tc_mt(cx, mt, cache)))
+            ty_ptr(ref mt) => {
+                tc_ty(cx, mt.ty, cache).other_pointer(TC::None)
+            }
+
+            ty_rptr(r, ref mt) => {
+                tc_ty(cx, mt.ty, cache).other_pointer(
+                    borrowed_contents(r, mt.mutbl))
             }
 
             ty_uniq(mt) => {
-                TC_OWNED_POINTER + statically_sized(tc_mt(cx, mt, cache))
+                tc_mt(cx, mt, cache).owned_pointer()
             }
 
             ty_evec(mt, vstore_uniq) => {
-                TC_OWNED_VEC + statically_sized(tc_mt(cx, mt, cache))
+                tc_mt(cx, mt, cache).owned_pointer()
             }
 
             ty_evec(mt, vstore_box) => {
-                TC_MANAGED +
-                    statically_sized(nonsendable(tc_mt(cx, mt, cache)))
+                tc_mt(cx, mt, cache).other_pointer(TC::Managed)
             }
 
-            ty_evec(mt, vstore_slice(r)) => {
-                borrowed_contents(r, mt.mutbl) +
-                    statically_sized(nonsendable(tc_mt(cx, mt, cache)))
+            ty_evec(ref mt, vstore_slice(r)) => {
+                tc_ty(cx, mt.ty, cache).other_pointer(
+                    borrowed_contents(r, mt.mutbl))
             }
 
             ty_evec(mt, vstore_fixed(_)) => {
-                let contents = tc_mt(cx, mt, cache);
-                // FIXME(#6308) Uncomment this when construction of such
-                // vectors is prevented earlier in compilation.
-                // if !contents.is_sized(cx) {
-                //     cx.sess.bug("Fixed-length vector of unsized type \
-                //                  should be impossible");
-                // }
-                contents
+                tc_mt(cx, mt, cache)
             }
 
             ty_estr(vstore_box) => {
-                TC_MANAGED
+                TC::Managed
             }
 
             ty_estr(vstore_slice(r)) => {
-                borrowed_contents(r, MutImmutable)
+                borrowed_contents(r, ast::MutImmutable)
             }
 
             ty_estr(vstore_fixed(_)) => {
-                TC_NONE
+                TC::None
             }
 
             ty_struct(did, ref substs) => {
                 let flds = struct_fields(cx, did, substs);
-                let mut res = flds.iter().fold(
-                    TC_NONE,
-                    |tc, f| tc + tc_mt(cx, f.mt, cache));
+                let mut res =
+                    TypeContents::union(flds, |f| tc_mt(cx, f.mt, cache));
                 if ty::has_dtor(cx, did) {
-                    res = res + TC_DTOR;
+                    res = res | TC::OwnsDtor;
                 }
-                apply_tc_attr(cx, did, res)
+                apply_attributes(cx, did, res)
             }
 
             ty_tup(ref tys) => {
-                tys.iter().fold(TC_NONE, |tc, ty| tc + tc_ty(cx, *ty, cache))
+                TypeContents::union(*tys, |ty| tc_ty(cx, *ty, cache))
             }
 
             ty_enum(did, ref substs) => {
                 let variants = substd_enum_variants(cx, did, substs);
-                let res = if variants.is_empty() {
-                    // we somewhat arbitrary declare that empty enums
-                    // are non-copyable
-                    TC_EMPTY_ENUM
-                } else {
-                    variants.iter().fold(TC_NONE, |tc, variant| {
-                        variant.args.iter().fold(tc,
-                            |tc, arg_ty| tc + tc_ty(cx, *arg_ty, cache))
-                    })
-                };
-                apply_tc_attr(cx, did, res)
+                let res =
+                    TypeContents::union(variants, |variant| {
+                        TypeContents::union(variant.args, |arg_ty| {
+                            tc_ty(cx, *arg_ty, cache)
+                        })
+                    });
+                apply_attributes(cx, did, res)
             }
 
             ty_param(p) => {
@@ -2175,7 +2185,8 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
                 assert_eq!(p.def_id.crate, ast::LOCAL_CRATE);
 
                 let tp_def = cx.ty_param_defs.get(&p.def_id.node);
-                kind_bounds_to_contents(cx, &tp_def.bounds.builtin_bounds,
+                kind_bounds_to_contents(cx,
+                                        tp_def.bounds.builtin_bounds,
                                         tp_def.bounds.trait_bounds)
             }
 
@@ -2186,31 +2197,29 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
                 // for supertraits. If so we can use those bounds.
                 let trait_def = lookup_trait_def(cx, def_id);
                 let traits = [trait_def.trait_ref];
-                kind_bounds_to_contents(cx, &trait_def.bounds, traits)
+                kind_bounds_to_contents(cx, trait_def.bounds, traits)
             }
 
             ty_infer(_) => {
                 // This occurs during coherence, but shouldn't occur at other
                 // times.
-                TC_ALL
+                TC::All
             }
 
-            ty_opaque_box => TC_MANAGED,
-            ty_unboxed_vec(mt) => TC_DYNAMIC_SIZE + tc_mt(cx, mt, cache),
+            ty_opaque_box => TC::Managed,
+            ty_unboxed_vec(mt) => TC::InteriorUnsized | tc_mt(cx, mt, cache),
             ty_opaque_closure_ptr(sigil) => {
                 match sigil {
-                    ast::BorrowedSigil => TC_BORROWED_POINTER,
-                    ast::ManagedSigil => TC_MANAGED,
-                    // FIXME(#3569): Looks like noncopyability should depend
-                    // on the bounds, but I don't think this case ever comes up.
-                    ast::OwnedSigil => TC_NONCOPY_TRAIT + TC_OWNED_POINTER,
+                    ast::BorrowedSigil => TC::ReachesBorrowed,
+                    ast::ManagedSigil => TC::Managed,
+                    ast::OwnedSigil => TC::OwnsOwned,
                 }
             }
 
-            ty_type => TC_NONE,
+            ty_type => TC::None,
 
             ty_err => {
-                cx.sess.bug("Asked to compute contents of fictitious type");
+                cx.sess.bug("Asked to compute contents of error type");
             }
         };
 
@@ -2222,132 +2231,105 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
              mt: mt,
              cache: &mut HashMap<uint, TypeContents>) -> TypeContents
     {
-        let mc = if mt.mutbl == MutMutable {TC_MUTABLE} else {TC_NONE};
-        mc + tc_ty(cx, mt.ty, cache)
+        let mc = TC::ReachesMutable.when(mt.mutbl == MutMutable);
+        mc | tc_ty(cx, mt.ty, cache)
     }
 
-    fn apply_tc_attr(cx: ctxt, did: DefId, mut tc: TypeContents) -> TypeContents {
-        if has_attr(cx, did, "no_freeze") {
-            tc = tc + TC_MUTABLE;
-        }
-        if has_attr(cx, did, "no_send") {
-            tc = tc + TC_NON_SENDABLE;
-        }
-        tc
+    fn apply_attributes(cx: ctxt,
+                        did: ast::DefId,
+                        tc: TypeContents)
+                        -> TypeContents {
+        tc |
+            TC::ReachesMutable.when(has_attr(cx, did, "no_freeze")) |
+            TC::ReachesNonsendAnnot.when(has_attr(cx, did, "no_send"))
     }
 
     fn borrowed_contents(region: ty::Region,
-                         mutbl: ast::Mutability) -> TypeContents
-    {
-        let mc = if mutbl == MutMutable {
-            TC_MUTABLE + TC_BORROWED_MUT
-        } else {
-            TC_NONE
-        };
-        let rc = if region != ty::re_static {
-            TC_BORROWED_POINTER
-        } else {
-            TC_NONE
-        };
-        mc + rc
-    }
-
-    fn nonsendable(pointee: TypeContents) -> TypeContents {
+                         mutbl: ast::Mutability)
+                         -> TypeContents {
         /*!
-         *
-         * Given a non-owning pointer to some type `T` with
-         * contents `pointee` (like `@T` or
-         * `&T`), returns the relevant bits that
-         * apply to the owner of the pointer.
+         * Type contents due to containing a borrowed pointer
+         * with the region `region` and borrow kind `bk`
          */
 
-        let mask = TC_MUTABLE.bits | TC_BORROWED_POINTER.bits;
-        TypeContents {bits: pointee.bits & mask}
-    }
-
-    fn statically_sized(pointee: TypeContents) -> TypeContents {
-        /*!
-         * If a dynamically-sized type is found behind a pointer, we should
-         * restore the 'Sized' kind to the pointer and things that contain it.
-         */
-        TypeContents {bits: pointee.bits & !TC_DYNAMIC_SIZE.bits}
+        let b = match mutbl {
+            ast::MutMutable => TC::ReachesMutable | TC::OwnsAffine,
+            ast::MutImmutable => TC::None,
+        };
+        b | (TC::ReachesBorrowed).when(region != ty::re_static)
     }
 
-    fn closure_contents(cty: &ClosureTy) -> TypeContents {
+    fn closure_contents(cx: ctxt, cty: &ClosureTy) -> TypeContents {
         // Closure contents are just like trait contents, but with potentially
         // even more stuff.
         let st = match cty.sigil {
             ast::BorrowedSigil =>
-                trait_contents(RegionTraitStore(cty.region), MutImmutable, cty.bounds)
-                    + TC_BORROWED_POINTER, // might be an env packet even if static
+                object_contents(cx, RegionTraitStore(cty.region), MutMutable, cty.bounds),
             ast::ManagedSigil =>
-                trait_contents(BoxTraitStore, MutImmutable, cty.bounds),
+                object_contents(cx, BoxTraitStore, MutImmutable, cty.bounds),
             ast::OwnedSigil =>
-                trait_contents(UniqTraitStore, MutImmutable, cty.bounds),
+                object_contents(cx, UniqTraitStore, MutImmutable, cty.bounds),
         };
+
         // FIXME(#3569): This borrowed_contents call should be taken care of in
-        // trait_contents, after ~Traits and @Traits can have region bounds too.
+        // object_contents, after ~Traits and @Traits can have region bounds too.
         // This one here is redundant for &fns but important for ~fns and @fns.
-        let rt = borrowed_contents(cty.region, MutImmutable);
+        let rt = borrowed_contents(cty.region, ast::MutImmutable);
+
         // This also prohibits "@once fn" from being copied, which allows it to
         // be called. Neither way really makes much sense.
         let ot = match cty.onceness {
-            ast::Once => TC_ONCE_CLOSURE,
-            ast::Many => TC_NONE
+            ast::Once => TC::OwnsAffine,
+            ast::Many => TC::None,
         };
-        // Prevent noncopyable types captured in the environment from being copied.
-        st + rt + ot + TC_NONCOPY_TRAIT
+
+        st | rt | ot
     }
 
-    fn trait_contents(store: TraitStore, mutbl: ast::Mutability,
-                      bounds: BuiltinBounds) -> TypeContents {
-        let st = match store {
-            UniqTraitStore      => TC_OWNED_POINTER,
-            BoxTraitStore       => TC_MANAGED,
-            RegionTraitStore(r) => borrowed_contents(r, mutbl),
-        };
-        let mt = match mutbl { ast::MutMutable => TC_MUTABLE, _ => TC_NONE };
-        // We get additional "special type contents" for each bound that *isn't*
-        // on the trait. So iterate over the inverse of the bounds that are set.
-        // This is like with typarams below, but less "pessimistic" and also
-        // dependent on the trait store.
-        let mut bt = TC_NONE;
-        for bound in (AllBuiltinBounds() - bounds).iter() {
-            bt = bt + match bound {
-                BoundStatic if bounds.contains_elem(BoundSend)
-                            => TC_NONE, // Send bound implies static bound.
-                BoundStatic => TC_BORROWED_POINTER, // Useful for "@Trait:'static"
-                BoundSend   => TC_NON_SENDABLE,
-                BoundFreeze => TC_MUTABLE,
-                BoundSized  => TC_NONE, // don't care if interior is sized
-            };
+    fn object_contents(cx: ctxt,
+                       store: TraitStore,
+                       mutbl: ast::Mutability,
+                       bounds: BuiltinBounds)
+                       -> TypeContents {
+        // These are the type contents of the (opaque) interior
+        let contents = (TC::ReachesMutable.when(mutbl == ast::MutMutable) |
+                        kind_bounds_to_contents(cx, bounds, []));
+
+        match store {
+            UniqTraitStore => {
+                contents.owned_pointer()
+            }
+            BoxTraitStore => {
+                contents.other_pointer(TC::Managed)
+            }
+            RegionTraitStore(r) => {
+                contents.other_pointer(borrowed_contents(r, mutbl))
+            }
         }
-        st + mt + bt
     }
 
-    fn kind_bounds_to_contents(cx: ctxt, bounds: &BuiltinBounds, traits: &[@TraitRef])
-            -> TypeContents {
+    fn kind_bounds_to_contents(cx: ctxt,
+                               bounds: BuiltinBounds,
+                               traits: &[@TraitRef])
+                               -> TypeContents {
         let _i = indenter();
-
-        let mut tc = TC_ALL;
+        let mut tc = TC::All;
         do each_inherited_builtin_bound(cx, bounds, traits) |bound| {
-            debug!("tc = {}, bound = {:?}", tc.to_str(), bound);
             tc = tc - match bound {
-                BoundStatic => TypeContents::nonstatic(cx),
-                BoundSend => TypeContents::nonsendable(cx),
-                BoundFreeze => TypeContents::nonfreezable(cx),
-                // The dynamic-size bit can be removed at pointer-level, etc.
-                BoundSized => TypeContents::dynamically_sized(cx),
+                BoundStatic => TC::Nonstatic,
+                BoundSend => TC::Nonsendable,
+                BoundFreeze => TC::Nonfreezable,
+                BoundSized => TC::Nonsized,
             };
         }
-
-        debug!("result = {}", tc.to_str());
         return tc;
 
         // Iterates over all builtin bounds on the type parameter def, including
         // those inherited from traits with builtin-kind-supertraits.
-        fn each_inherited_builtin_bound(cx: ctxt, bounds: &BuiltinBounds,
-                                        traits: &[@TraitRef], f: &fn(BuiltinBound)) {
+        fn each_inherited_builtin_bound(cx: ctxt,
+                                        bounds: BuiltinBounds,
+                                        traits: &[@TraitRef],
+                                        f: &fn(BuiltinBound)) {
             for bound in bounds.iter() {
                 f(bound);
             }
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 96783318481..32284584b65 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -3732,7 +3732,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
                ty::mk_nil())
             }
             "needs_drop" => (1u, ~[], ty::mk_bool()),
-            "contains_managed" => (1u, ~[], ty::mk_bool()),
+            "owns_managed" => (1u, ~[], ty::mk_bool()),
             "atomic_xchg"     | "atomic_xadd"     | "atomic_xsub"     |
             "atomic_xchg_acq" | "atomic_xadd_acq" | "atomic_xsub_acq" |
             "atomic_xchg_rel" | "atomic_xadd_rel" | "atomic_xsub_rel" => {
diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs
index 15d5fe702a5..3f119bc8ccb 100644
--- a/src/librustuv/uvio.rs
+++ b/src/librustuv/uvio.rs
@@ -414,10 +414,10 @@ impl UvIoFactory {
 /// callback in a situation where the task wil be immediately blocked
 /// afterwards. The `FsCallback` yielded must be invoked to reschedule the task
 /// (once the result of the operation is known).
-fn uv_fs_helper<T>(loop_: &mut Loop,
-                   retfn: extern "Rust" fn(&mut FsRequest) -> T,
-                   cb: &fn(&mut FsRequest, &mut Loop, FsCallback))
-        -> Result<T, IoError> {
+fn uv_fs_helper<T:Send>(loop_: &mut Loop,
+                        retfn: extern "Rust" fn(&mut FsRequest) -> T,
+                        cb: &fn(&mut FsRequest, &mut Loop, FsCallback))
+                        -> Result<T, IoError> {
     let result_cell = Cell::new_empty();
     let result_cell_ptr: *Cell<Result<T, IoError>> = &result_cell;
     do task::unkillable { // FIXME(#8674)
@@ -1025,14 +1025,12 @@ fn read_stream(mut watcher: StreamWatcher,
     let result_cell = Cell::new_empty();
     let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell;
 
-    let buf_ptr: *&mut [u8] = &buf;
+    let uv_buf = slice_to_uv_buf(buf);
     do scheduler.deschedule_running_task_and_then |_sched, task| {
         let task_cell = Cell::new(task);
         // XXX: We shouldn't reallocate these callbacks every
         // call to read
-        let alloc: AllocCallback = |_| unsafe {
-            slice_to_uv_buf(*buf_ptr)
-        };
+        let alloc: AllocCallback = |_| uv_buf;
         do watcher.read_start(alloc) |mut watcher, nread, _buf, status| {
 
             // Stop reading so that no read callbacks are
@@ -1280,11 +1278,10 @@ impl RtioUdpSocket for UvUdpSocket {
         do self.home_for_io_with_sched |self_, scheduler| {
             let result_cell = Cell::new_empty();
             let result_cell_ptr: *Cell<Result<(uint, SocketAddr), IoError>> = &result_cell;
-
-            let buf_ptr: *&mut [u8] = &buf;
+            let uv_buf = slice_to_uv_buf(buf);
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let task_cell = Cell::new(task);
-                let alloc: AllocCallback = |_| unsafe { slice_to_uv_buf(*buf_ptr) };
+                let alloc: AllocCallback = |_| uv_buf;
                 do self_.watcher.recv_start(alloc) |mut watcher, nread, _buf, addr, flags, status| {
                     let _ = flags; // /XXX add handling for partials?
 
diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs
index 404ed85985c..030364c75af 100644
--- a/src/libstd/unstable/intrinsics.rs
+++ b/src/libstd/unstable/intrinsics.rs
@@ -337,8 +337,13 @@ extern "rust-intrinsic" {
     pub fn needs_drop<T>() -> bool;
 
     /// Returns `true` if a type is managed (will be allocated on the local heap)
+    #[cfg(stage0)]
     pub fn contains_managed<T>() -> bool;
 
+    /// Returns `true` if a type is managed (will be allocated on the local heap)
+    #[cfg(not(stage0))]
+    pub fn owns_managed<T>() -> bool;
+
     pub fn visit_tydesc(td: *TyDesc, tv: &mut TyVisitor);
 
     /// Get the address of the `__morestack` stack growth function.
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs
index b10d0ded5b4..c9d55735015 100644
--- a/src/libstd/vec.rs
+++ b/src/libstd/vec.rs
@@ -121,11 +121,19 @@ use mem::size_of;
 use uint;
 use unstable::finally::Finally;
 use unstable::intrinsics;
-use unstable::intrinsics::{get_tydesc, contains_managed};
+use unstable::intrinsics::{get_tydesc};
 use unstable::raw::{Box, Repr, Slice, Vec};
 use vec;
 use util;
 
+#[cfg(not(stage0))]
+use unstable::intrinsics::owns_managed;
+
+#[cfg(stage0)]
+unsafe fn owns_managed<T>() -> bool {
+    intrinsics::contains_managed::<T>()
+}
+
 /**
  * Creates and initializes an owned vector.
  *
@@ -180,7 +188,7 @@ pub fn from_elem<T:Clone>(n_elts: uint, t: T) -> ~[T] {
 #[inline]
 pub fn with_capacity<T>(capacity: uint) -> ~[T] {
     unsafe {
-        if contains_managed::<T>() {
+        if owns_managed::<T>() {
             let mut vec = ~[];
             vec.reserve(capacity);
             vec
@@ -1401,7 +1409,7 @@ impl<T> OwnedVector<T> for ~[T] {
         if self.capacity() < n {
             unsafe {
                 let td = get_tydesc::<T>();
-                if contains_managed::<T>() {
+                if owns_managed::<T>() {
                     let ptr: *mut *mut Box<Vec<()>> = cast::transmute(self);
                     ::at_vec::raw::reserve_raw(td, ptr, n);
                 } else {
@@ -1437,7 +1445,7 @@ impl<T> OwnedVector<T> for ~[T] {
     #[inline]
     fn capacity(&self) -> uint {
         unsafe {
-            if contains_managed::<T>() {
+            if owns_managed::<T>() {
                 let repr: **Box<Vec<()>> = cast::transmute(self);
                 (**repr).data.alloc / mem::nonzero_size_of::<T>()
             } else {
@@ -1460,7 +1468,7 @@ impl<T> OwnedVector<T> for ~[T] {
     #[inline]
     fn push(&mut self, t: T) {
         unsafe {
-            if contains_managed::<T>() {
+            if owns_managed::<T>() {
                 let repr: **Box<Vec<()>> = cast::transmute(&mut *self);
                 let fill = (**repr).data.fill;
                 if (**repr).data.alloc <= fill {
@@ -1482,7 +1490,7 @@ impl<T> OwnedVector<T> for ~[T] {
         // This doesn't bother to make sure we have space.
         #[inline] // really pretty please
         unsafe fn push_fast<T>(this: &mut ~[T], t: T) {
-            if contains_managed::<T>() {
+            if owns_managed::<T>() {
                 let repr: **mut Box<Vec<u8>> = cast::transmute(this);
                 let fill = (**repr).data.fill;
                 (**repr).data.fill += mem::nonzero_size_of::<T>();
@@ -2057,9 +2065,14 @@ pub mod raw {
     use mem;
     use unstable::intrinsics;
     use vec::{with_capacity, ImmutableVector, MutableVector};
-    use unstable::intrinsics::contains_managed;
     use unstable::raw::{Box, Vec, Slice};
 
+    #[cfg(not(stage0))]
+    use unstable::intrinsics::owns_managed;
+
+    #[cfg(stage0)]
+    use vec::owns_managed;
+
     /**
      * Sets the length of a vector
      *
@@ -2069,7 +2082,7 @@ pub mod raw {
      */
     #[inline]
     pub unsafe fn set_len<T>(v: &mut ~[T], new_len: uint) {
-        if contains_managed::<T>() {
+        if owns_managed::<T>() {
             let repr: **mut Box<Vec<()>> = cast::transmute(v);
             (**repr).data.fill = new_len * mem::nonzero_size_of::<T>();
         } else {
diff --git a/src/test/compile-fail/kindck-freeze.rs b/src/test/compile-fail/kindck-freeze.rs
new file mode 100644
index 00000000000..c83892e2a3b
--- /dev/null
+++ b/src/test/compile-fail/kindck-freeze.rs
@@ -0,0 +1,56 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test which of the builtin types are considered freezeable.
+
+fn assert_freeze<T:Freeze>() { }
+trait Dummy { }
+
+fn test<'a,T,U:Freeze>(_: &'a int) {
+    // lifetime pointers are ok...
+    assert_freeze::<&'static int>();
+    assert_freeze::<&'a int>();
+    assert_freeze::<&'a str>();
+    assert_freeze::<&'a [int]>();
+
+    // ...unless they are mutable
+    assert_freeze::<&'static mut int>(); //~ ERROR does not fulfill `Freeze`
+    assert_freeze::<&'a mut int>(); //~ ERROR does not fulfill `Freeze`
+
+    // ~ pointers are ok
+    assert_freeze::<~int>();
+    assert_freeze::<~str>();
+    assert_freeze::<~[int]>();
+
+    // but not if they own a bad thing
+    assert_freeze::<~&'a mut int>(); //~ ERROR does not fulfill `Freeze`
+
+    // careful with object types, who knows what they close over...
+    assert_freeze::<&'a Dummy>(); //~ ERROR does not fulfill `Freeze`
+    assert_freeze::<~Dummy>(); //~ ERROR does not fulfill `Freeze`
+
+    // ...unless they are properly bounded
+    assert_freeze::<&'a Dummy:Freeze>();
+    assert_freeze::<&'static Dummy:Freeze>();
+    assert_freeze::<~Dummy:Freeze>();
+
+    // ...but even then the pointer overrides
+    assert_freeze::<&'a mut Dummy:Freeze>(); //~ ERROR does not fulfill `Freeze`
+
+    // closures are like an `&mut` object
+    assert_freeze::<&fn()>(); //~ ERROR does not fulfill `Freeze`
+
+    // unsafe ptrs are ok unless they point at unfreezeable things
+    assert_freeze::<*int>();
+    assert_freeze::<*&'a mut int>(); //~ ERROR does not fulfill `Freeze`
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/kindck-send.rs b/src/test/compile-fail/kindck-send.rs
new file mode 100644
index 00000000000..bb5851ac5c8
--- /dev/null
+++ b/src/test/compile-fail/kindck-send.rs
@@ -0,0 +1,59 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test which of the builtin types are considered sendable.
+
+fn assert_send<T:Send>() { }
+trait Dummy { }
+
+fn test<'a,T,U:Send>(_: &'a int) {
+    // lifetime pointers with 'static lifetime are ok
+    assert_send::<&'static int>();
+    assert_send::<&'static str>();
+    assert_send::<&'static [int]>();
+
+    // whether or not they are mutable
+    assert_send::<&'static mut int>();
+
+    // otherwise lifetime pointers are not ok
+    assert_send::<&'a int>(); //~ ERROR does not fulfill `Send`
+    assert_send::<&'a str>(); //~ ERROR does not fulfill `Send`
+    assert_send::<&'a [int]>(); //~ ERROR does not fulfill `Send`
+
+    // ~ pointers are ok
+    assert_send::<~int>();
+    assert_send::<~str>();
+    assert_send::<~[int]>();
+
+    // but not if they own a bad thing
+    assert_send::<~&'a int>(); //~ ERROR does not fulfill `Send`
+
+    // careful with object types, who knows what they close over...
+    assert_send::<&'static Dummy>(); //~ ERROR does not fulfill `Send`
+    assert_send::<&'a Dummy>(); //~ ERROR does not fulfill `Send`
+    assert_send::<&'a Dummy:Send>(); //~ ERROR does not fulfill `Send`
+    assert_send::<~Dummy:>(); //~ ERROR does not fulfill `Send`
+
+    // ...unless they are properly bounded
+    assert_send::<&'static Dummy:Send>();
+    assert_send::<~Dummy:Send>();
+
+    // but closure and object types can have lifetime bounds which make
+    // them not ok (FIXME #5121)
+    // assert_send::<~fn:'a()>(); // ERROR does not fulfill `Send`
+    // assert_send::<~Dummy:'a>(); // ERROR does not fulfill `Send`
+
+    // unsafe ptrs are ok unless they point at unsendable things
+    assert_send::<*int>();
+    assert_send::<*&'a int>(); //~ ERROR does not fulfill `Send`
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/mutable-enum-indirect.rs b/src/test/compile-fail/mutable-enum-indirect.rs
new file mode 100644
index 00000000000..9fad05387c6
--- /dev/null
+++ b/src/test/compile-fail/mutable-enum-indirect.rs
@@ -0,0 +1,12 @@
+// Tests that an `&` pointer to something inherently mutable is itself
+// to be considered mutable.
+
+#[no_freeze]
+enum Foo { A }
+
+fn bar<T: Freeze>(_: T) {}
+
+fn main() {
+    let x = A;
+    bar(&x); //~ ERROR type parameter with an incompatible type
+}