Skip to content

Commit 074799b

Browse files
committed
Implement a lint mode to detect unnecessary allocations
1 parent 26babaa commit 074799b

File tree

2 files changed

+73
-3
lines changed

2 files changed

+73
-3
lines changed

src/librustc/middle/lint.rs

+70
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ pub enum lint {
7979
unused_variable,
8080
dead_assignment,
8181
unused_mut,
82+
unnecessary_allocation,
8283
}
8384

8485
pub fn level_to_str(lv: level) -> &'static str {
@@ -242,6 +243,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
242243
desc: "detect mut variables which don't need to be mutable",
243244
default: warn
244245
}),
246+
247+
("unnecessary_allocation",
248+
LintSpec {
249+
lint: unnecessary_allocation,
250+
desc: "detects unnecessary allocations that can be eliminated",
251+
default: warn
252+
}),
245253
];
246254

247255
/*
@@ -881,6 +889,67 @@ fn lint_session(cx: @mut Context) -> visit::vt<()> {
881889
})
882890
}
883891

892+
fn lint_unnecessary_allocations(cx: @mut Context) -> visit::vt<()> {
893+
// If the expression `e` has an allocated type, but `t` dictates that it's
894+
// something like a slice (doesn't need allocation), emit a warning with the
895+
// specified span.
896+
//
897+
// Currently, this only applies to string and vector literals with sigils in
898+
// front. Those can have the sigil removed to get a borrowed pointer
899+
// automatically.
900+
fn check(cx: @mut Context, e: @ast::expr, t: ty::t) {
901+
match e.node {
902+
ast::expr_vstore(e2, ast::expr_vstore_uniq) |
903+
ast::expr_vstore(e2, ast::expr_vstore_box) => {
904+
match e2.node {
905+
ast::expr_lit(@codemap::spanned{
906+
node: ast::lit_str(*), _}) |
907+
ast::expr_vec(*) => {}
908+
_ => return
909+
}
910+
}
911+
912+
_ => return
913+
}
914+
915+
match ty::get(t).sty {
916+
ty::ty_estr(ty::vstore_slice(*)) |
917+
ty::ty_evec(_, ty::vstore_slice(*)) => {
918+
cx.span_lint(unnecessary_allocation,
919+
e.span, "unnecessary allocation, the sigil can be \
920+
removed");
921+
}
922+
923+
_ => ()
924+
}
925+
}
926+
927+
let visit_expr: @fn(@ast::expr) = |e| {
928+
match e.node {
929+
ast::expr_call(c, ref args, _) => {
930+
let t = ty::node_id_to_type(cx.tcx, c.id);
931+
let s = ty::ty_fn_sig(t);
932+
for vec::each2(*args, s.inputs) |e, t| {
933+
check(cx, *e, *t);
934+
}
935+
}
936+
ast::expr_method_call(_, _, _, ref args, _) => {
937+
let t = ty::node_id_to_type(cx.tcx, e.callee_id);
938+
let s = ty::ty_fn_sig(t);
939+
for vec::each2(*args, s.inputs) |e, t| {
940+
check(cx, *e, *t);
941+
}
942+
}
943+
_ => {}
944+
}
945+
};
946+
947+
visit::mk_simple_visitor(@visit::SimpleVisitor {
948+
visit_expr: visit_expr,
949+
.. *visit::default_simple_visitor()
950+
})
951+
}
952+
884953
pub fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
885954
let cx = @mut Context {
886955
dict: @get_lint_dict(),
@@ -908,6 +977,7 @@ pub fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
908977
cx.add_lint(lint_unused_unsafe(cx));
909978
cx.add_lint(lint_unused_mut(cx));
910979
cx.add_lint(lint_session(cx));
980+
cx.add_lint(lint_unnecessary_allocations(cx));
911981

912982
// type inference doesn't like this being declared below, we need to tell it
913983
// what the type of this first function is...

src/libsyntax/ext/env.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use ast;
1818
use codemap::span;
1919
use ext::base::*;
2020
use ext::base;
21-
use ext::build::mk_uniq_str;
21+
use ext::build::mk_base_str;
2222

2323
pub fn expand_syntax_ext(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
2424
-> base::MacResult {
@@ -29,8 +29,8 @@ pub fn expand_syntax_ext(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
2929
// Option<str> rather than just an maybe-empty string.
3030

3131
let e = match os::getenv(var) {
32-
None => mk_uniq_str(cx, sp, ~""),
33-
Some(ref s) => mk_uniq_str(cx, sp, copy *s)
32+
None => mk_base_str(cx, sp, ~""),
33+
Some(ref s) => mk_base_str(cx, sp, copy *s)
3434
};
3535
MRExpr(e)
3636
}

0 commit comments

Comments
 (0)