diff --git a/src/rustc/middle/kind.rs b/src/rustc/middle/kind.rs index 4c66809c16fe..8eace4f5cf11 100644 --- a/src/rustc/middle/kind.rs +++ b/src/rustc/middle/kind.rs @@ -286,6 +286,7 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt) { maybe_copy(cx, source, Some(("casted values must be copyable", try_adding))); check_cast_for_escaping_regions(cx, source, e); + check_kind_bounds_of_cast(cx, source, e); } expr_copy(expr) => check_copy_ex(cx, expr, false, Some(("explicit copy requires a copyable argument", ""))), @@ -607,6 +608,26 @@ fn check_cast_for_escaping_regions( } } +/// Ensures that values placed into a ~Trait are copyable and sendable. +fn check_kind_bounds_of_cast(cx: ctx, source: @expr, target: @expr) { + let target_ty = ty::expr_ty(cx.tcx, target); + match ty::get(target_ty).sty { + ty::ty_trait(_, _, ty::vstore_uniq) => { + let source_ty = ty::expr_ty(cx.tcx, source); + let source_kind = ty::type_kind(cx.tcx, source_ty); + if !ty::kind_can_be_copied(source_kind) { + cx.tcx.sess.span_err(target.span, + ~"uniquely-owned trait objects must be copyable"); + } + if !ty::kind_can_be_sent(source_kind) { + cx.tcx.sess.span_err(target.span, + ~"uniquely-owned trait objects must be sendable"); + } + } + _ => {} // Nothing to do. + } +} + // // Local Variables: // mode: rust diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs index 7f234349d711..b02d12e0b736 100644 --- a/src/rustc/middle/trans/common.rs +++ b/src/rustc/middle/trans/common.rs @@ -971,10 +971,15 @@ fn T_captured_tydescs(cx: @crate_ctxt, n: uint) -> TypeRef { fn T_opaque_trait(cx: @crate_ctxt, vstore: ty::vstore) -> TypeRef { match vstore { - ty::vstore_box => - T_struct(~[T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)]), - _ => - T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())]) + ty::vstore_box => { + T_struct(~[T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)]) + } + ty::vstore_uniq => { + T_struct(~[T_ptr(cx.tydesc_type), + T_unique_ptr(T_unique(cx, T_i8())), + T_ptr(cx.tydesc_type)]) + } + _ => T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())]) } } diff --git a/src/rustc/middle/trans/expr.rs b/src/rustc/middle/trans/expr.rs index 519aa9c44ecd..1bd44ee4bda6 100644 --- a/src/rustc/middle/trans/expr.rs +++ b/src/rustc/middle/trans/expr.rs @@ -614,7 +614,16 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, DontAutorefArg); } ast::expr_cast(val, _) => { - return meth::trans_trait_cast(bcx, val, expr.id, dest); + match ty::get(node_id_type(bcx, expr.id)).sty { + ty::ty_trait(_, _, vstore) => { + return meth::trans_trait_cast(bcx, val, expr.id, dest, + vstore); + } + _ => { + bcx.tcx().sess.span_bug(expr.span, + ~"expr_cast of non-trait"); + } + } } ast::expr_assign_op(op, dst, src) => { return trans_assign_op(bcx, expr, op, dst, src); diff --git a/src/rustc/middle/trans/glue.rs b/src/rustc/middle/trans/glue.rs index af9f2899a54d..76d5770ac3d2 100644 --- a/src/rustc/middle/trans/glue.rs +++ b/src/rustc/middle/trans/glue.rs @@ -482,7 +482,11 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { decr_refcnt_maybe_free(bcx, llbox, ty::mk_opaque_box(ccx.tcx)) } ty::ty_trait(_, _, ty::vstore_uniq) => { - ccx.tcx.sess.unimpl(~"drop of unique trait"); + let lluniquevalue = GEPi(bcx, v0, [0, 1]); + let lltydesc = Load(bcx, GEPi(bcx, v0, [0, 2])); + call_tydesc_glue_full(bcx, lluniquevalue, lltydesc, + abi::tydesc_field_free_glue, None); + bcx } ty::ty_opaque_closure_ptr(ck) => { closure::make_opaque_cbox_drop_glue(bcx, ck, v0) @@ -536,11 +540,18 @@ fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) { ty::ty_fn(_) => { closure::make_fn_glue(bcx, v, t, take_ty) } - ty::ty_trait(_, _, _) => { + ty::ty_trait(_, _, ty::vstore_box) => { let llbox = Load(bcx, GEPi(bcx, v, [0u, 1u])); incr_refcnt_of_boxed(bcx, llbox); bcx } + ty::ty_trait(_, _, ty::vstore_uniq) => { + let llval = GEPi(bcx, v, [0, 1]); + let lltydesc = Load(bcx, GEPi(bcx, v, [0, 2])); + call_tydesc_glue_full(bcx, llval, lltydesc, + abi::tydesc_field_take_glue, None); + bcx + } ty::ty_opaque_closure_ptr(ck) => { closure::make_opaque_cbox_take_glue(bcx, ck, v) } diff --git a/src/rustc/middle/trans/meth.rs b/src/rustc/middle/trans/meth.rs index e7c134fe5469..ea85453a445b 100644 --- a/src/rustc/middle/trans/meth.rs +++ b/src/rustc/middle/trans/meth.rs @@ -650,7 +650,8 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: ~[ty::t], fn trans_trait_cast(bcx: block, val: @ast::expr, id: ast::node_id, - dest: expr::Dest) + dest: expr::Dest, + vstore: ty::vstore) -> block { let mut bcx = bcx; @@ -666,25 +667,54 @@ fn trans_trait_cast(bcx: block, let ccx = bcx.ccx(); let v_ty = expr_ty(bcx, val); - let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]); - if bcx.tcx().legacy_boxed_traits.contains_key(id) { - // Allocate an @ box and store the value into it - let {bcx: new_bcx, box: llbox, body: body} = malloc_boxed(bcx, v_ty); - bcx = new_bcx; - add_clean_free(bcx, llbox, heap_shared); - bcx = expr::trans_into(bcx, val, SaveIn(body)); - revoke_clean(bcx, llbox); + match vstore { + ty::vstore_slice(*) | ty::vstore_box => { + let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]); + if bcx.tcx().legacy_boxed_traits.contains_key(id) { + // Allocate an @ box and store the value into it + let {bcx: new_bcx, box: llbox, body: body} = + malloc_boxed(bcx, v_ty); + bcx = new_bcx; + add_clean_free(bcx, llbox, heap_shared); + bcx = expr::trans_into(bcx, val, SaveIn(body)); + revoke_clean(bcx, llbox); - // Store the @ box into the pair - Store(bcx, llbox, PointerCast(bcx, llboxdest, T_ptr(val_ty(llbox)))); - } else { - // Just store the @ box into the pair. - llboxdest = PointerCast(bcx, llboxdest, - T_ptr(type_of::type_of(bcx.ccx(), v_ty))); - bcx = expr::trans_into(bcx, val, SaveIn(llboxdest)); + // Store the @ box into the pair + Store(bcx, llbox, PointerCast(bcx, + llboxdest, + T_ptr(val_ty(llbox)))); + } else { + // Just store the pointer into the pair. + llboxdest = PointerCast(bcx, + llboxdest, + T_ptr(type_of::type_of(bcx.ccx(), + v_ty))); + bcx = expr::trans_into(bcx, val, SaveIn(llboxdest)); + } + } + ty::vstore_uniq => { + // Translate the uniquely-owned value into the second element of + // the triple. (The first element is the vtable.) + let mut llvaldest = GEPi(bcx, lldest, [0, 1]); + llvaldest = PointerCast(bcx, + llvaldest, + T_ptr(type_of::type_of(bcx.ccx(), v_ty))); + bcx = expr::trans_into(bcx, val, SaveIn(llvaldest)); + + // Get the type descriptor of the wrapped value and store it into + // the third element of the triple as well. + let tydesc = get_tydesc(bcx.ccx(), v_ty); + glue::lazily_emit_all_tydesc_glue(bcx.ccx(), tydesc); + let lltydescdest = GEPi(bcx, lldest, [0, 2]); + Store(bcx, tydesc.tydesc, lltydescdest); + } + _ => { + bcx.tcx().sess.span_bug(val.span, ~"unexpected vstore in \ + trans_trait_cast"); + } } - // Store the vtable into the pair + // Store the vtable into the pair or triple. let orig = ccx.maps.vtable_map.get(id)[0]; let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig); let vtable = get_vtable(bcx.ccx(), orig); diff --git a/src/rustc/middle/typeck/astconv.rs b/src/rustc/middle/typeck/astconv.rs index da7a71b3efbf..d793955e447d 100644 --- a/src/rustc/middle/typeck/astconv.rs +++ b/src/rustc/middle/typeck/astconv.rs @@ -190,13 +190,14 @@ fn ast_ty_to_ty( match ty::get(result.ty).sty { ty::ty_trait(trait_def_id, substs, _) => { match vst { - ty::vstore_box | ty::vstore_slice(*) => {} + ty::vstore_box | ty::vstore_slice(*) | + ty::vstore_uniq => {} _ => { - tcx.sess.span_unimpl(path.span, - ~"`~trait` is \ - unimplemented; use \ - `@trait` instead for \ - now"); + tcx.sess.span_err(path.span, + ~"@trait, ~trait or &trait \ + are the only supported \ + forms of casting-to-\ + trait"); } } return ty::mk_trait(tcx, trait_def_id, substs, vst); diff --git a/src/rustc/middle/typeck/check/vtable.rs b/src/rustc/middle/typeck/check/vtable.rs index a033a80a8d45..b6f51b4b2c74 100644 --- a/src/rustc/middle/typeck/check/vtable.rs +++ b/src/rustc/middle/typeck/check/vtable.rs @@ -540,14 +540,18 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) { None => { // Try the new-style boxed trait; "@int as @Trait". // Or the new-style region trait; "&int as &Trait". + // Or the new-style uniquely-owned trait; "~int as + // ~Trait". let mut err = false; let ty = structurally_resolved_type(fcx, ex.span, ty); match ty::get(ty).sty { - ty::ty_box(mt) | ty::ty_rptr(_, mt) => { + ty::ty_box(mt) | ty::ty_rptr(_, mt) | + ty::ty_uniq(mt) => { // Ensure that the trait vstore and the pointer // type match. match (ty::get(ty).sty, vstore) { (ty::ty_box(_), ty::vstore_box) | + (ty::ty_uniq(_), ty::vstore_uniq) | (ty::ty_rptr(*), ty::vstore_slice(*)) => { let vtable_opt = lookup_vtable_invariant(fcx, @@ -600,6 +604,14 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) { a borrowed \ trait"); } + (ty::ty_uniq(*), _) => { + fcx.ccx.tcx.sess.span_err(ex.span, + ~"must cast \ + a unique \ + pointer to \ + a uniquely-\ + owned trait"); + } _ => { fcx.ccx.tcx.sess.impossible_case( ex.span, diff --git a/src/test/compile-fail/unique-object-noncopyable.rs b/src/test/compile-fail/unique-object-noncopyable.rs new file mode 100644 index 000000000000..2d4c391841bf --- /dev/null +++ b/src/test/compile-fail/unique-object-noncopyable.rs @@ -0,0 +1,21 @@ +trait Foo { + fn f(); +} + +struct Bar { + x: int, + drop {} +} + +impl Bar : Foo { + fn f() { + io::println("hi"); + } +} + +fn main() { + let x = ~Bar { x: 10 }; + let y = (move x) as ~Foo; //~ ERROR uniquely-owned trait objects must be copyable + let _z = copy y; +} + diff --git a/src/test/run-pass/unique-object.rs b/src/test/run-pass/unique-object.rs new file mode 100644 index 000000000000..952ecde35d18 --- /dev/null +++ b/src/test/run-pass/unique-object.rs @@ -0,0 +1,22 @@ +trait Foo { + fn f(); +} + +struct Bar { + x: int +} + +impl Bar : Foo { + fn f() { + io::println("hi"); + } +} + +fn main() { + let x = ~Bar { x: 10 }; + let y = x as ~Foo; + let z = copy y; + y.f(); + z.f(); +} +