Skip to content

Commit cc8086a

Browse files
committed
add new deprecated_mode lint pass
It will warn you if you use the default mode for something that is expensive to copy, and it will warn you if you use any explicit mode other than copy. So you should migrate over to using the default mode for most things (and borrowed pointers when you don't want to copy) and copy mode for things you really wanted to copy.
1 parent 99674dc commit cc8086a

File tree

2 files changed

+161
-21
lines changed

2 files changed

+161
-21
lines changed

src/rustc/middle/lint.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import syntax::codemap::span;
77
import std::map::{map,hashmap,int_hash,hash_from_strs};
88
import std::smallintmap::{map,smallintmap};
99
import io::writer_util;
10-
import syntax::print::pprust::expr_to_str;
10+
import util::ppaux::{ty_to_str};
11+
import syntax::print::pprust::{expr_to_str, mode_to_str};
1112
export lint, ctypes, unused_imports, while_true, path_statement, old_vecs;
1213
export unrecognized_warning, non_implicitly_copyable_typarams;
1314
export vecs_not_implicitly_copyable, implicit_copies;
@@ -47,6 +48,7 @@ enum lint {
4748
unrecognized_warning,
4849
non_implicitly_copyable_typarams,
4950
vecs_not_implicitly_copyable,
51+
deprecated_mode,
5052
}
5153

5254
// This is pretty unfortunate. We really want some sort of "deriving Enum"
@@ -61,6 +63,7 @@ fn int_to_lint(i: int) -> lint {
6163
5 { unrecognized_warning }
6264
6 { non_implicitly_copyable_typarams }
6365
7 { vecs_not_implicitly_copyable }
66+
8 { deprecated_mode }
6467
}
6568
}
6669

@@ -119,8 +122,12 @@ fn get_lint_dict() -> lint_dict {
119122
(~"implicit_copies",
120123
@{lint: implicit_copies,
121124
desc: ~"implicit copies of non implicitly copyable data",
122-
default: warn})
125+
default: warn}),
123126

127+
(~"deprecated_mode",
128+
@{lint: deprecated_mode,
129+
desc: ~"warn about deprecated uses of modes",
130+
default: ignore})
124131
];
125132
hash_from_strs(v)
126133
}
@@ -411,10 +418,56 @@ fn check_item_path_statement(cx: ty::ctxt, it: @ast::item) {
411418
visit::visit_item(it, (), visit);
412419
}
413420

421+
fn check_fn(tcx: ty::ctxt, fk: visit::fn_kind, decl: ast::fn_decl,
422+
_body: ast::blk, span: span, id: ast::node_id) {
423+
#debug["lint check_fn fk=%? id=%?", fk, id];
424+
let fn_ty = ty::node_id_to_type(tcx, id);
425+
alt check ty::get(fn_ty).struct {
426+
ty::ty_fn(fn_ty) {
427+
let mut counter = 0;
428+
do vec::iter2(fn_ty.inputs, decl.inputs) |arg_ty, arg_ast| {
429+
counter += 1;
430+
#debug["arg %d, ty=%s, mode=%s",
431+
counter,
432+
ty_to_str(tcx, arg_ty.ty),
433+
mode_to_str(arg_ast.mode)];
434+
alt arg_ast.mode {
435+
ast::expl(ast::by_copy) => {
436+
/* always allow by-copy */
437+
}
438+
439+
ast::expl(_) => {
440+
tcx.sess.span_lint(
441+
deprecated_mode, id, id,
442+
span,
443+
#fmt["argument %d uses an explicit mode", counter]);
444+
}
445+
446+
ast::infer(_) {
447+
let kind = ty::type_kind(tcx, arg_ty.ty);
448+
if !ty::kind_is_safe_for_default_mode(kind) {
449+
tcx.sess.span_lint(
450+
deprecated_mode, id, id,
451+
span,
452+
#fmt["argument %d uses the default mode \
453+
but shouldn't",
454+
counter]);
455+
}
456+
}
457+
}
458+
}
459+
}
460+
}
461+
}
462+
414463
fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
415464

416465
let v = visit::mk_simple_visitor(@{
417-
visit_item: fn@(it: @ast::item) { check_item(it, tcx); }
466+
visit_item:
467+
|it| check_item(it, tcx),
468+
visit_fn:
469+
|fk, decl, body, span, id| check_fn(tcx, fk, decl, body,
470+
span, id),
418471
with *visit::default_simple_visitor()
419472
});
420473
visit::visit_crate(*crate, (), v);

src/rustc/middle/ty.rs

Lines changed: 105 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export ty_fn_args;
110110
export kind, kind_implicitly_copyable, kind_send_copy, kind_copyable;
111111
export kind_noncopyable, kind_const;
112112
export kind_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied;
113+
export kind_is_safe_for_default_mode;
113114
export kind_is_owned;
114115
export proto_kind, kind_lteq, type_kind;
115116
export operators;
@@ -1371,19 +1372,22 @@ fn type_needs_unwind_cleanup_(cx: ctxt, ty: t,
13711372
enum kind { kind_(u32) }
13721373

13731374
/// can be copied (implicitly or explicitly)
1374-
const KIND_MASK_COPY : u32 = 0b00000000000000000000000000000001_u32;
1375+
const KIND_MASK_COPY : u32 = 0b000000000000000000000000001_u32;
13751376

13761377
/// can be sent: no shared box, borrowed ptr (must imply OWNED)
1377-
const KIND_MASK_SEND : u32 = 0b00000000000000000000000000000010_u32;
1378+
const KIND_MASK_SEND : u32 = 0b000000000000000000000000010_u32;
13781379

13791380
/// is owned (no borrowed ptrs)
1380-
const KIND_MASK_OWNED : u32 = 0b00000000000000000000000000000100_u32;
1381+
const KIND_MASK_OWNED : u32 = 0b000000000000000000000000100_u32;
13811382

13821383
/// is deeply immutable
1383-
const KIND_MASK_CONST : u32 = 0b00000000000000000000000000001000_u32;
1384+
const KIND_MASK_CONST : u32 = 0b000000000000000000000001000_u32;
13841385

13851386
/// can be implicitly copied (must imply COPY)
1386-
const KIND_MASK_IMPLICIT : u32 = 0b00000000000000000000000000010000_u32;
1387+
const KIND_MASK_IMPLICIT : u32 = 0b000000000000000000000010000_u32;
1388+
1389+
/// safe for default mode (subset of KIND_MASK_IMPLICIT)
1390+
const KIND_MASK_DEFAULT_MODE : u32 = 0b000000000000000000000100000_u32;
13871391

13881392
fn kind_noncopyable() -> kind {
13891393
kind_(0u32)
@@ -1397,10 +1401,22 @@ fn kind_implicitly_copyable() -> kind {
13971401
kind_(KIND_MASK_IMPLICIT | KIND_MASK_COPY)
13981402
}
13991403

1404+
fn kind_safe_for_default_mode() -> kind {
1405+
// similar to implicit copy, but always includes vectors and strings
1406+
kind_(KIND_MASK_DEFAULT_MODE | KIND_MASK_IMPLICIT | KIND_MASK_COPY)
1407+
}
1408+
14001409
fn kind_implicitly_sendable() -> kind {
14011410
kind_(KIND_MASK_IMPLICIT | KIND_MASK_COPY | KIND_MASK_SEND)
14021411
}
14031412

1413+
fn kind_safe_for_default_mode_send() -> kind {
1414+
// similar to implicit copy, but always includes vectors and strings
1415+
kind_(KIND_MASK_DEFAULT_MODE | KIND_MASK_IMPLICIT |
1416+
KIND_MASK_COPY | KIND_MASK_SEND)
1417+
}
1418+
1419+
14041420
fn kind_send_copy() -> kind {
14051421
kind_(KIND_MASK_COPY | KIND_MASK_SEND)
14061422
}
@@ -1426,7 +1442,7 @@ fn remove_const(k: kind) -> kind {
14261442
}
14271443

14281444
fn remove_implicit(k: kind) -> kind {
1429-
k - kind_(KIND_MASK_IMPLICIT)
1445+
k - kind_(KIND_MASK_IMPLICIT | KIND_MASK_DEFAULT_MODE)
14301446
}
14311447

14321448
fn remove_send(k: kind) -> kind {
@@ -1462,6 +1478,10 @@ pure fn kind_can_be_implicitly_copied(k: kind) -> bool {
14621478
*k & KIND_MASK_IMPLICIT == KIND_MASK_IMPLICIT
14631479
}
14641480

1481+
pure fn kind_is_safe_for_default_mode(k: kind) -> bool {
1482+
*k & KIND_MASK_DEFAULT_MODE == KIND_MASK_DEFAULT_MODE
1483+
}
1484+
14651485
pure fn kind_can_be_copied(k: kind) -> bool {
14661486
*k & KIND_MASK_COPY == KIND_MASK_COPY
14671487
}
@@ -1478,9 +1498,9 @@ fn proto_kind(p: proto) -> kind {
14781498
alt p {
14791499
ast::proto_any { kind_noncopyable() }
14801500
ast::proto_block { kind_noncopyable() }
1481-
ast::proto_box { kind_implicitly_copyable() | kind_owned() }
1501+
ast::proto_box { kind_safe_for_default_mode() | kind_owned() }
14821502
ast::proto_uniq { kind_send_copy() | kind_owned() }
1483-
ast::proto_bare { kind_implicitly_sendable() | kind_const() |
1503+
ast::proto_bare { kind_safe_for_default_mode_send() | kind_const() |
14841504
kind_owned() }
14851505
}
14861506
}
@@ -1539,11 +1559,11 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
15391559
// Insert a default in case we loop back on self recursively.
15401560
cx.kind_cache.insert(ty, kind_top());
15411561

1542-
let result = alt get(ty).struct {
1562+
let mut result = alt get(ty).struct {
15431563
// Scalar and unique types are sendable, constant, and owned
15441564
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
15451565
ty_ptr(_) {
1546-
kind_implicitly_sendable() | kind_const() | kind_owned()
1566+
kind_safe_for_default_mode_send() | kind_const() | kind_owned()
15471567
}
15481568

15491569
// Implicit copyability of strs is configurable
@@ -1561,14 +1581,14 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
15611581
// Those with refcounts raise noncopyable to copyable,
15621582
// lower sendable to copyable. Therefore just set result to copyable.
15631583
ty_box(tm) {
1564-
remove_send(mutable_type_kind(cx, tm) | kind_implicitly_copyable())
1584+
remove_send(mutable_type_kind(cx, tm) | kind_safe_for_default_mode())
15651585
}
15661586

15671587
// Iface instances are (for now) like shared boxes, basically
1568-
ty_trait(_, _) { kind_implicitly_copyable() | kind_owned() }
1588+
ty_trait(_, _) { kind_safe_for_default_mode() | kind_owned() }
15691589

15701590
// Region pointers are copyable but NOT owned nor sendable
1571-
ty_rptr(_, _) { kind_implicitly_copyable() }
1591+
ty_rptr(_, _) { kind_safe_for_default_mode() }
15721592

15731593
// Unique boxes and vecs have the kind of their contained type,
15741594
// but unique boxes can't be implicitly copyable.
@@ -1587,10 +1607,10 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
15871607
// contained type, but aren't implicitly copyable. Fixed vectors have
15881608
// the kind of the element they contain, taking mutability into account.
15891609
ty_evec(tm, vstore_box) {
1590-
remove_send(kind_implicitly_copyable() | mutable_type_kind(cx, tm))
1610+
remove_send(kind_safe_for_default_mode() | mutable_type_kind(cx, tm))
15911611
}
15921612
ty_evec(tm, vstore_slice(_)) {
1593-
remove_owned_send(kind_implicitly_copyable() |
1613+
remove_owned_send(kind_safe_for_default_mode() |
15941614
mutable_type_kind(cx, tm))
15951615
}
15961616
ty_evec(tm, vstore_fixed(_)) {
@@ -1599,13 +1619,13 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
15991619

16001620
// All estrs are copyable; uniques and interiors are sendable.
16011621
ty_estr(vstore_box) {
1602-
kind_implicitly_copyable() | kind_const() | kind_owned()
1622+
kind_safe_for_default_mode() | kind_const() | kind_owned()
16031623
}
16041624
ty_estr(vstore_slice(_)) {
1605-
kind_implicitly_copyable() | kind_const()
1625+
kind_safe_for_default_mode() | kind_const()
16061626
}
16071627
ty_estr(vstore_fixed(_)) {
1608-
kind_implicitly_sendable() | kind_const() | kind_owned()
1628+
kind_safe_for_default_mode_send() | kind_const() | kind_owned()
16091629
}
16101630

16111631
// Records lower to the lowest of their members.
@@ -1676,10 +1696,77 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
16761696
}
16771697
};
16781698

1699+
// arbitrary threshold to prevent by-value copying of big records
1700+
if kind_is_safe_for_default_mode(result) {
1701+
if type_size(cx, ty) > 4 {
1702+
result -= kind_(KIND_MASK_DEFAULT_MODE);
1703+
}
1704+
}
1705+
16791706
cx.kind_cache.insert(ty, result);
16801707
ret result;
16811708
}
16821709

1710+
/// gives a rough estimate of how much space it takes to represent
1711+
/// an instance of `ty`. Used for the mode transition.
1712+
fn type_size(cx: ctxt, ty: t) -> uint {
1713+
alt get(ty).struct {
1714+
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
1715+
ty_ptr(_) | ty_box(_) | ty_uniq(_) | ty_estr(vstore_uniq) |
1716+
ty_trait(*) | ty_rptr(*) | ty_evec(_, vstore_uniq) |
1717+
ty_evec(_, vstore_box) | ty_estr(vstore_box) => {
1718+
1
1719+
}
1720+
1721+
ty_evec(_, vstore_slice(_)) |
1722+
ty_estr(vstore_slice(_)) |
1723+
ty_fn(_) => {
1724+
2
1725+
}
1726+
1727+
ty_evec(t, vstore_fixed(n)) => {
1728+
type_size(cx, t.ty) * n
1729+
}
1730+
1731+
ty_estr(vstore_fixed(n)) => {
1732+
n
1733+
}
1734+
1735+
ty_rec(flds) => {
1736+
flds.foldl(0, |s, f| s + type_size(cx, f.mt.ty))
1737+
}
1738+
1739+
ty_class(did, substs) {
1740+
let flds = class_items_as_fields(cx, did, substs);
1741+
flds.foldl(0, |s, f| s + type_size(cx, f.mt.ty))
1742+
}
1743+
1744+
ty_tup(tys) {
1745+
tys.foldl(0, |s, t| s + type_size(cx, t))
1746+
}
1747+
1748+
ty_enum(did, substs) {
1749+
let variants = substd_enum_variants(cx, did, substs);
1750+
variants.foldl( // find max size of any variant
1751+
0,
1752+
|m, v| uint::max(m,
1753+
// find size of this variant:
1754+
v.args.foldl(0, |s, a| s + type_size(cx, a))))
1755+
}
1756+
1757+
ty_param(_) | ty_self {
1758+
1
1759+
}
1760+
1761+
ty_var(_) | ty_var_integral(_) {
1762+
cx.sess.bug(~"Asked to compute kind of a type variable");
1763+
}
1764+
ty_type | ty_opaque_closure_ptr(_) | ty_opaque_box | ty_unboxed_vec(_) {
1765+
cx.sess.bug(~"Asked to compute kind of fictitious type");
1766+
}
1767+
}
1768+
}
1769+
16831770
// True if instantiating an instance of `r_ty` requires an instance of `r_ty`.
16841771
fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
16851772

0 commit comments

Comments
 (0)