Skip to content

Commit 93633ea

Browse files
committed
Add an internal notion of 'implicit copyability' and use it to warn when implicitly copying mutable data and some unique data. Closes #2448.
1 parent 8668d06 commit 93633ea

File tree

2 files changed

+104
-46
lines changed

2 files changed

+104
-46
lines changed

src/rustc/middle/kind.rs

+20-14
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
9292
check_send(cx, var_t, sp);
9393

9494
// copied in data must be copyable, but moved in data can be anything
95-
if !is_move { check_copy(cx, var_t, sp); }
95+
let is_implicit = fv.is_some();
96+
if !is_move { check_copy(cx, var_t, sp, is_implicit); }
9697

9798
// check that only immutable variables are implicitly copied in
9899
if !is_move {
@@ -105,7 +106,8 @@ fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
105106
fn check_for_box(cx: ctx, fv: option<@freevar_entry>, is_move: bool,
106107
var_t: ty::t, sp: span) {
107108
// copied in data must be copyable, but moved in data can be anything
108-
if !is_move { check_copy(cx, var_t, sp); }
109+
let is_implicit = fv.is_some();
110+
if !is_move { check_copy(cx, var_t, sp, is_implicit); }
109111

110112
// check that only immutable variables are implicitly copied in
111113
if !is_move {
@@ -203,12 +205,16 @@ fn check_block(b: blk, cx: ctx, v: visit::vt<ctx>) {
203205
fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
204206
#debug["kind::check_expr(%s)", expr_to_str(e)];
205207
alt e.node {
206-
expr_assign(_, ex) | expr_assign_op(_, _, ex) |
208+
expr_assign(_, ex) |
207209
expr_unary(box(_), ex) | expr_unary(uniq(_), ex) |
208210
expr_ret(some(ex)) | expr_cast(ex, _) { maybe_copy(cx, ex); }
209211
expr_copy(expr) { check_copy_ex(cx, expr, false); }
210-
// Vector add copies.
211-
expr_binary(add, ls, rs) { maybe_copy(cx, ls); maybe_copy(cx, rs); }
212+
// Vector add copies, but not "implicitly"
213+
expr_assign_op(_, _, ex) { check_copy_ex(cx, ex, false) }
214+
expr_binary(add, ls, rs) {
215+
check_copy_ex(cx, ls, false);
216+
check_copy_ex(cx, rs, false);
217+
}
212218
expr_rec(fields, def) {
213219
for fields.each {|field| maybe_copy(cx, field.node.expr); }
214220
alt def {
@@ -365,17 +371,12 @@ fn is_nullary_variant(cx: ctx, ex: @expr) -> bool {
365371
}
366372
}
367373

368-
fn check_copy_ex(cx: ctx, ex: @expr, _warn: bool) {
374+
fn check_copy_ex(cx: ctx, ex: @expr, implicit_copy: bool) {
369375
if ty::expr_is_lval(cx.method_map, ex) &&
370376
!cx.last_use_map.contains_key(ex.id) &&
371377
!is_nullary_variant(cx, ex) {
372378
let ty = ty::expr_ty(cx.tcx, ex);
373-
check_copy(cx, ty, ex.span);
374-
// FIXME turn this on again once vector types are no longer unique.
375-
// Right now, it is too annoying to be useful.
376-
/* if warn && ty::type_is_unique(ty) {
377-
cx.tcx.sess.span_warn(ex.span, "copying a unique value");
378-
}*/
379+
check_copy(cx, ty, ex.span, implicit_copy);
379380
}
380381
}
381382

@@ -408,9 +409,14 @@ fn check_imm_free_var(cx: ctx, def: def, sp: span) {
408409
}
409410
}
410411

411-
fn check_copy(cx: ctx, ty: ty::t, sp: span) {
412-
if !ty::kind_can_be_copied(ty::type_kind(cx.tcx, ty)) {
412+
fn check_copy(cx: ctx, ty: ty::t, sp: span, implicit_copy: bool) {
413+
let k = ty::type_kind(cx.tcx, ty);
414+
if !ty::kind_can_be_copied(k) {
413415
cx.tcx.sess.span_err(sp, "copying a noncopyable value");
416+
} else if implicit_copy && !ty::kind_can_be_implicitly_copied(k) {
417+
cx.tcx.sess.span_warn(
418+
sp,
419+
"implicitly copying a non-implicitly-copyable value");
414420
}
415421
}
416422

src/rustc/middle/ty.rs

+84-32
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ export ty_to_def_id;
111111
export ty_fn_args;
112112
export type_constr;
113113
export kind, kind_sendable, kind_copyable, kind_noncopyable, kind_const;
114-
export kind_can_be_copied, kind_can_be_sent, proto_kind, kind_lteq, type_kind;
114+
export kind_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied;
115+
export proto_kind, kind_lteq, type_kind;
115116
export operators;
116117
export type_err, terr_vstore_kind;
117118
export type_err_to_str;
@@ -1268,9 +1269,11 @@ fn type_needs_unwind_cleanup_(cx: ctxt, ty: t,
12681269

12691270
enum kind { kind_(u32) }
12701271

1271-
const KIND_MASK_COPY : u32 = 0b00000000000000000000000000000001u32;
1272-
const KIND_MASK_SEND : u32 = 0b00000000000000000000000000000010u32;
1273-
const KIND_MASK_CONST : u32 = 0b00000000000000000000000000000100u32;
1272+
// *ALL* implicity copiable things must be copiable
1273+
const KIND_MASK_COPY : u32 = 0b00000000000000000000000000000001u32;
1274+
const KIND_MASK_SEND : u32 = 0b00000000000000000000000000000010u32;
1275+
const KIND_MASK_CONST : u32 = 0b00000000000000000000000000000100u32;
1276+
const KIND_MASK_IMPLICIT : u32 = 0b00000000000000000000000000001000u32;
12741277

12751278
fn kind_noncopyable() -> kind {
12761279
kind_(0u32)
@@ -1280,6 +1283,14 @@ fn kind_copyable() -> kind {
12801283
kind_(KIND_MASK_COPY)
12811284
}
12821285

1286+
fn kind_implicitly_copyable() -> kind {
1287+
kind_(KIND_MASK_IMPLICIT | KIND_MASK_COPY)
1288+
}
1289+
1290+
fn kind_implicitly_sendable() -> kind {
1291+
kind_(KIND_MASK_IMPLICIT | KIND_MASK_COPY | KIND_MASK_SEND)
1292+
}
1293+
12831294
fn kind_sendable() -> kind {
12841295
kind_(KIND_MASK_COPY | KIND_MASK_SEND)
12851296
}
@@ -1305,6 +1316,10 @@ fn remove_const(k: kind, tm: mt) -> kind {
13051316
}
13061317
}
13071318

1319+
fn remove_implicit(k: kind) -> kind {
1320+
k - kind_(KIND_MASK_IMPLICIT)
1321+
}
1322+
13081323
impl operators for kind {
13091324
fn &(other: kind) -> kind {
13101325
lower_kind(self, other)
@@ -1319,9 +1334,13 @@ impl operators for kind {
13191334
}
13201335
}
13211336

1322-
// Using these query functons is preferable to direct comparison or matching
1337+
// Using these query functions is preferable to direct comparison or matching
13231338
// against the kind constants, as we may modify the kind hierarchy in the
13241339
// future.
1340+
pure fn kind_can_be_implicitly_copied(k: kind) -> bool {
1341+
*k & KIND_MASK_IMPLICIT != 0u32
1342+
}
1343+
13251344
pure fn kind_can_be_copied(k: kind) -> bool {
13261345
*k & KIND_MASK_COPY != 0u32
13271346
}
@@ -1334,9 +1353,9 @@ fn proto_kind(p: proto) -> kind {
13341353
alt p {
13351354
ast::proto_any { kind_noncopyable() }
13361355
ast::proto_block { kind_noncopyable() }
1337-
ast::proto_box { kind_copyable() }
1356+
ast::proto_box { kind_implicitly_copyable() }
13381357
ast::proto_uniq { kind_sendable() }
1339-
ast::proto_bare { kind_sendable() | kind_const() }
1358+
ast::proto_bare { kind_implicitly_sendable() | kind_const() }
13401359
}
13411360
}
13421361

@@ -1354,13 +1373,34 @@ fn raise_kind(a: kind, b: kind) -> kind {
13541373

13551374
#[test]
13561375
fn test_kinds() {
1357-
// The kind "lattice" is nocopy <= copy <= send
1376+
// The kind "lattice" is defined by the subset operation on the
1377+
// set of permitted operations.
13581378
assert kind_lteq(kind_sendable(), kind_sendable());
13591379
assert kind_lteq(kind_copyable(), kind_sendable());
13601380
assert kind_lteq(kind_copyable(), kind_copyable());
13611381
assert kind_lteq(kind_noncopyable(), kind_sendable());
13621382
assert kind_lteq(kind_noncopyable(), kind_copyable());
13631383
assert kind_lteq(kind_noncopyable(), kind_noncopyable());
1384+
assert kind_lteq(kind_copyable(), kind_implicitly_copyable());
1385+
assert kind_lteq(kind_copyable(), kind_implicitly_sendable());
1386+
assert kind_lteq(kind_sendable(), kind_implicitly_sendable());
1387+
assert !kind_lteq(kind_sendable(), kind_implicitly_copyable());
1388+
assert !kind_lteq(kind_copyable(), kind_send_only());
1389+
}
1390+
1391+
// Return the most permissive kind that a composite object containing a field
1392+
// with the given mutability can have.
1393+
// This is used to prevent objects containing mutable state from being
1394+
// implicitly copied.
1395+
fn mutability_kind(m: mutability) -> kind {
1396+
alt (m) {
1397+
m_mutbl | m_const { remove_implicit(kind_top()) }
1398+
m_imm { kind_top() }
1399+
}
1400+
}
1401+
1402+
fn mutable_type_kind(cx: ctxt, ty: mt) -> kind {
1403+
lower_kind(mutability_kind(ty.mutbl), type_kind(cx, ty.ty))
13641404
}
13651405

13661406
fn type_kind(cx: ctxt, ty: t) -> kind {
@@ -1370,79 +1410,88 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
13701410
}
13711411

13721412
// Insert a default in case we loop back on self recursively.
1373-
cx.kind_cache.insert(ty, kind_sendable());
1413+
cx.kind_cache.insert(ty, kind_top());
13741414

13751415
let result = alt get(ty).struct {
13761416
// Scalar and unique types are sendable
13771417
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
1378-
ty_ptr(_) | ty_str { kind_sendable() | kind_const() }
1418+
ty_ptr(_) { kind_implicitly_sendable() | kind_const() }
1419+
// FIXME: this *shouldn't* be implicitly copyable (#2450)
1420+
ty_str { kind_implicitly_sendable() | kind_const() }
13791421
ty_type { kind_copyable() }
13801422
ty_fn(f) { proto_kind(f.proto) }
13811423

13821424
// Closures have kind determined by capture mode
13831425
ty_opaque_closure_ptr(ck_block) { kind_noncopyable() }
1384-
ty_opaque_closure_ptr(ck_box) { kind_copyable() }
1426+
ty_opaque_closure_ptr(ck_box) { kind_implicitly_copyable() }
13851427
ty_opaque_closure_ptr(ck_uniq) { kind_sendable() }
13861428

13871429
// Those with refcounts raise noncopyable to copyable,
13881430
// lower sendable to copyable. Therefore just set result to copyable.
13891431
ty_box(tm) {
13901432
if tm.mutbl == ast::m_mutbl {
1391-
kind_copyable()
1433+
kind_implicitly_copyable()
13921434
}
13931435
else {
13941436
let k = type_kind(cx, tm.ty);
13951437
if kind_lteq(kind_const(), k) {
1396-
kind_copyable() | kind_const()
1438+
kind_implicitly_copyable() | kind_const()
13971439
}
1398-
else { kind_copyable() }
1440+
else { kind_implicitly_copyable() }
13991441
}
14001442
}
1401-
ty_iface(_, _) | ty_opaque_box { kind_copyable() }
1402-
ty_rptr(_, _) { kind_copyable() }
1443+
ty_iface(_, _) | ty_opaque_box { kind_implicitly_copyable() }
1444+
ty_rptr(_, _) { kind_implicitly_copyable() }
14031445

1404-
// Unique boxes and vecs have the kind of their contained type.
1405-
ty_vec(tm) | ty_uniq(tm) { remove_const(type_kind(cx, tm.ty), tm) }
1446+
// Unique boxes and vecs have the kind of their contained type,
1447+
// but unique boxes can't be implicitly copyable.
1448+
ty_uniq(tm) {
1449+
remove_implicit(remove_const(type_kind(cx, tm.ty), tm))
1450+
}
1451+
// FIXME: Vectors *shouldn't* be implicitly copyable but are (#2450)
1452+
ty_vec(tm) { remove_const(mutable_type_kind(cx, tm), tm) }
14061453

14071454
// Slice and refcounted evecs are copyable; uniques and interiors
1408-
// depend on the their contained type.
1455+
// depend on the their contained type, but aren't implicitly copyable.
14091456
ty_evec(tm, vstore_box) |
14101457
ty_evec(tm, vstore_slice(_)) {
14111458
if kind_lteq(kind_const(), type_kind(cx, tm.ty)) {
1412-
kind_copyable() | kind_const()
1459+
kind_implicitly_copyable() | kind_const()
14131460
}
14141461
else {
1415-
kind_const()
1462+
kind_implicitly_copyable()
14161463
}
14171464
}
14181465
ty_evec(tm, vstore_uniq) |
1419-
ty_evec(tm, vstore_fixed(_)) { remove_const(type_kind(cx, tm.ty), tm) }
1466+
ty_evec(tm, vstore_fixed(_)) {
1467+
remove_implicit(remove_const(type_kind(cx, tm.ty), tm))
1468+
}
14201469

14211470
// All estrs are copyable; uniques and interiors are sendable.
14221471
ty_estr(vstore_box) |
1423-
ty_estr(vstore_slice(_)) { kind_copyable() | kind_const() }
1472+
ty_estr(vstore_slice(_)) { kind_implicitly_copyable() | kind_const() }
14241473
ty_estr(vstore_uniq) |
14251474
ty_estr(vstore_fixed(_)) { kind_sendable() | kind_const() }
14261475

14271476
// Records lower to the lowest of their members.
14281477
ty_rec(flds) {
14291478
let mut lowest = kind_top();
14301479
for flds.each {|f|
1431-
lowest = lower_kind(lowest, type_kind(cx, f.mt.ty));
1480+
lowest = lower_kind(lowest, mutable_type_kind(cx, f.mt));
14321481
lowest = remove_const(lowest, f.mt);
14331482
}
14341483
lowest
14351484
}
14361485
// FIXME: (tjc) there are rules about when classes are copyable/
14371486
// sendable, but I'm just treating them like records (#1726)
14381487
ty_class(did, substs) {
1439-
// also factor out this code, copied from the records case
1440-
let mut lowest = kind_top();
1441-
let flds = class_items_as_fields(cx, did, substs);
1442-
for flds.each {|f|
1443-
lowest = lower_kind(lowest, type_kind(cx, f.mt.ty));
1444-
}
1445-
lowest
1488+
// also factor out this code, copied from the records case
1489+
let mut lowest = kind_top();
1490+
let flds = class_items_as_fields(cx, did, substs);
1491+
for flds.each {|f|
1492+
lowest = lower_kind(lowest, mutable_type_kind(cx, f.mt));
1493+
}
1494+
lowest
14461495
}
14471496
// Tuples lower to the lowest of their members.
14481497
ty_tup(tys) {
@@ -1470,7 +1519,10 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
14701519
}
14711520
ty_res(did, inner, tps) { kind_send_only() }
14721521
ty_param(_, did) {
1473-
param_bounds_to_kind(cx.ty_param_bounds.get(did.node))
1522+
// FIXME: type params shouldn't be implicitly copyable (#2449)
1523+
let k = param_bounds_to_kind(cx.ty_param_bounds.get(did.node));
1524+
if kind_can_be_copied(k)
1525+
{ raise_kind(k, kind_implicitly_copyable()) } else { k }
14741526
}
14751527
ty_constr(t, _) { type_kind(cx, t) }
14761528
// FIXME: is self ever const?

0 commit comments

Comments
 (0)