diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index a36d938052a91..9bafea6d861be 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 64a4c453b2deb..37e4d4e82be51 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 f036f922de9cc..9629615c64dd9 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 d57c24e37d57e..1efa7f763d8f9 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 3e17bc1b585a1..c6a33864620ad 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 02b44907f336a..f461120e4c38a 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 3d1c74028cc3b..a7af10b491ee6 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 c56d88355495f..2f4fcfed20be9 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 1f9e903717931..93718fc1a2382 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 2a8d16a2ceb83..604321a0492a1 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 93335de229275..8ff270e236fa5 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 6c2fb2f095c2e..96bb2897e0e26 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(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 for TypeContents { + fn bitor(&self, other: &TypeContents) -> TypeContents { + TypeContents {bits: self.bits | other.bits} } } -impl ops::Add for TypeContents { - fn add(&self, other: &TypeContents) -> TypeContents { - TypeContents {bits: self.bits | other.bits} +impl ops::BitAnd 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 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 would also yield TC_NONE + // requests for the contents of Option 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) -> 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 9678331848100..32284584b6583 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 15d5fe702a536..3f119bc8ccbf0 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(loop_: &mut Loop, - retfn: extern "Rust" fn(&mut FsRequest) -> T, - cb: &fn(&mut FsRequest, &mut Loop, FsCallback)) - -> Result { +fn uv_fs_helper(loop_: &mut Loop, + retfn: extern "Rust" fn(&mut FsRequest) -> T, + cb: &fn(&mut FsRequest, &mut Loop, FsCallback)) + -> Result { let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &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_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_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 404ed85985c42..030364c75af4b 100644 --- a/src/libstd/unstable/intrinsics.rs +++ b/src/libstd/unstable/intrinsics.rs @@ -337,8 +337,13 @@ extern "rust-intrinsic" { pub fn needs_drop() -> bool; /// Returns `true` if a type is managed (will be allocated on the local heap) + #[cfg(stage0)] pub fn contains_managed() -> bool; + /// Returns `true` if a type is managed (will be allocated on the local heap) + #[cfg(not(stage0))] + pub fn owns_managed() -> 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 b10d0ded5b477..c9d557350151e 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() -> bool { + intrinsics::contains_managed::() +} + /** * Creates and initializes an owned vector. * @@ -180,7 +188,7 @@ pub fn from_elem(n_elts: uint, t: T) -> ~[T] { #[inline] pub fn with_capacity(capacity: uint) -> ~[T] { unsafe { - if contains_managed::() { + if owns_managed::() { let mut vec = ~[]; vec.reserve(capacity); vec @@ -1401,7 +1409,7 @@ impl OwnedVector for ~[T] { if self.capacity() < n { unsafe { let td = get_tydesc::(); - if contains_managed::() { + if owns_managed::() { let ptr: *mut *mut Box> = cast::transmute(self); ::at_vec::raw::reserve_raw(td, ptr, n); } else { @@ -1437,7 +1445,7 @@ impl OwnedVector for ~[T] { #[inline] fn capacity(&self) -> uint { unsafe { - if contains_managed::() { + if owns_managed::() { let repr: **Box> = cast::transmute(self); (**repr).data.alloc / mem::nonzero_size_of::() } else { @@ -1460,7 +1468,7 @@ impl OwnedVector for ~[T] { #[inline] fn push(&mut self, t: T) { unsafe { - if contains_managed::() { + if owns_managed::() { let repr: **Box> = cast::transmute(&mut *self); let fill = (**repr).data.fill; if (**repr).data.alloc <= fill { @@ -1482,7 +1490,7 @@ impl OwnedVector for ~[T] { // This doesn't bother to make sure we have space. #[inline] // really pretty please unsafe fn push_fast(this: &mut ~[T], t: T) { - if contains_managed::() { + if owns_managed::() { let repr: **mut Box> = cast::transmute(this); let fill = (**repr).data.fill; (**repr).data.fill += mem::nonzero_size_of::(); @@ -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(v: &mut ~[T], new_len: uint) { - if contains_managed::() { + if owns_managed::() { let repr: **mut Box> = cast::transmute(v); (**repr).data.fill = new_len * mem::nonzero_size_of::(); } else { diff --git a/src/test/compile-fail/kindck-freeze.rs b/src/test/compile-fail/kindck-freeze.rs new file mode 100644 index 0000000000000..c83892e2a3b31 --- /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 or the MIT license +// , 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() { } +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 0000000000000..bb5851ac5c8f1 --- /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 or the MIT license +// , 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() { } +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 0000000000000..9fad05387c6b4 --- /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) {} + +fn main() { + let x = A; + bar(&x); //~ ERROR type parameter with an incompatible type +}