Skip to content

Commit aba93c6

Browse files
committed
auto merge of #5966 : alexcrichton/rust/issue-3083, r=graydon
Closes #3083. This takes a similar approach to #5797 where a set is present on the `tcx` of used mutable definitions. Everything is by default warned about, and analyses must explicitly add mutable definitions to this set so they're not warned about. Most of this was pretty straightforward, although there was one caveat that I ran into when implementing it. Apparently when the old modes are used (or maybe `legacy_modes`, I'm not sure) some different code paths are taken to cause spurious warnings to be issued which shouldn't be issued. I'm not really sure how modes even worked, so I was having a lot of trouble tracking this down. I figured that because they're a legacy thing that I'd just de-mode the compiler so that the warnings wouldn't be a problem anymore (or at least for the compiler). Other than that, the entire compiler compiles without warnings of unused mutable variables. To prevent bad warnings, #5965 should be landed (which in turn is waiting on #5963) before landing this. I figured I'd stick it out for review anyway though.
2 parents a6dd7dc + c389d0b commit aba93c6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+265
-120
lines changed

src/libcore/cell.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ fn test_with_ref() {
121121
#[test]
122122
fn test_with_mut_ref() {
123123
let good = ~[1, 2, 3];
124-
let mut v = ~[1, 2];
124+
let v = ~[1, 2];
125125
let c = Cell(v);
126126
do c.with_mut_ref() |v| { v.push(3); }
127127
let v = c.take();

src/libcore/flate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ pub fn deflate_bytes(bytes: &const [u8]) -> ~[u8] {
6767
pub fn inflate_bytes(bytes: &const [u8]) -> ~[u8] {
6868
do vec::as_const_buf(bytes) |b, len| {
6969
unsafe {
70-
let mut outsz : size_t = 0;
70+
let outsz : size_t = 0;
7171
let res =
7272
rustrt::tinfl_decompress_mem_to_heap(b as *c_void,
7373
len as size_t,

src/libcore/path.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ pub mod windows {
854854
while i < s.len() {
855855
if is_sep(s[i]) {
856856
let pre = s.slice(2, i).to_owned();
857-
let mut rest = s.slice(i, s.len()).to_owned();
857+
let rest = s.slice(i, s.len()).to_owned();
858858
return Some((pre, rest));
859859
}
860860
i += 1;

src/libcore/rand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ struct XorShiftState {
742742
impl Rng for XorShiftState {
743743
fn next(&self) -> u32 {
744744
let x = self.x;
745-
let mut t = x ^ (x << 11);
745+
let t = x ^ (x << 11);
746746
self.x = self.y;
747747
self.y = self.z;
748748
self.z = self.w;

src/libcore/repr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ pub impl ReprVisitor {
210210
#[inline(always)]
211211
fn visit_ptr_inner(&self, ptr: *c_void, inner: *TyDesc) -> bool {
212212
unsafe {
213-
let mut u = ReprVisitor(ptr, self.writer);
213+
let u = ReprVisitor(ptr, self.writer);
214214
let v = reflect::MovePtrAdaptor(u);
215215
visit_tydesc(inner, @v as @TyVisitor);
216216
true
@@ -667,7 +667,7 @@ pub fn write_repr<T>(writer: @Writer, object: &T) {
667667
unsafe {
668668
let ptr = ptr::to_unsafe_ptr(object) as *c_void;
669669
let tydesc = intrinsic::get_tydesc::<T>();
670-
let mut u = ReprVisitor(ptr, writer);
670+
let u = ReprVisitor(ptr, writer);
671671
let v = reflect::MovePtrAdaptor(u);
672672
visit_tydesc(tydesc, @v as @TyVisitor)
673673
}

src/libcore/rt/uv/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ fn loop_smoke_test() {
402402
fn idle_new_then_close() {
403403
do run_in_bare_thread {
404404
let mut loop_ = Loop::new();
405-
let mut idle_watcher = { IdleWatcher::new(&mut loop_) };
405+
let idle_watcher = { IdleWatcher::new(&mut loop_) };
406406
idle_watcher.close();
407407
}
408408
}

src/libcore/rt/uv/net.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ fn connect_read() {
393393
let buf = vec_from_uv_buf(buf);
394394
rtdebug!("read cb!");
395395
if status.is_none() {
396-
let bytes = buf.unwrap();
396+
let _bytes = buf.unwrap();
397397
rtdebug!("%s", bytes.slice(0, nread as uint).to_str());
398398
} else {
399399
rtdebug!("status after read: %s", status.get().to_str());

src/libcore/rt/uvio.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ impl TcpListener for UvTcpListener {
206206
let mut server_stream_watcher = server_stream_watcher;
207207
let mut loop_ = loop_from_watcher(&server_stream_watcher);
208208
let mut client_tcp_watcher = TcpWatcher::new(&mut loop_);
209-
let mut client_tcp_watcher = client_tcp_watcher.as_stream();
209+
let client_tcp_watcher = client_tcp_watcher.as_stream();
210210
// XXX: Need's to be surfaced in interface
211211
server_stream_watcher.accept(client_tcp_watcher);
212212
Some(~UvStream::new(client_tcp_watcher))

src/libcore/run.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
343343
fn force_destroy(&mut self) { destroy_repr(&mut self.r, true); }
344344
}
345345

346-
let mut repr = ProgRepr {
346+
let repr = ProgRepr {
347347
pid: pid,
348348
in_fd: pipe_input.out,
349349
out_file: os::fdopen(pipe_output.in),

src/libcore/str.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ pub fn levdistance(s: &str, t: &str) -> uint {
673673

674674
for t.each_chari |j, tc| {
675675

676-
let mut next = dcol[j + 1];
676+
let next = dcol[j + 1];
677677

678678
if sc == tc {
679679
dcol[j + 1] = current;
@@ -909,7 +909,7 @@ impl TotalOrd for @str {
909909
/// Bytewise slice less than
910910
fn lt(a: &str, b: &str) -> bool {
911911
let (a_len, b_len) = (a.len(), b.len());
912-
let mut end = uint::min(a_len, b_len);
912+
let end = uint::min(a_len, b_len);
913913

914914
let mut i = 0;
915915
while i < end {
@@ -1715,7 +1715,7 @@ pub fn utf16_chars(v: &[u16], f: &fn(char)) {
17151715
let len = vec::len(v);
17161716
let mut i = 0u;
17171717
while (i < len && v[i] != 0u16) {
1718-
let mut u = v[i];
1718+
let u = v[i];
17191719

17201720
if u <= 0xD7FF_u16 || u >= 0xE000_u16 {
17211721
f(u as char);

src/libcore/task/spawn.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ fn spawn_raw_oldsched(opts: TaskOpts, f: ~fn()) {
575575
};
576576
assert!(!new_task.is_null());
577577
// Getting killed after here would leak the task.
578-
let mut notify_chan = if opts.notify_chan.is_none() {
578+
let notify_chan = if opts.notify_chan.is_none() {
579579
None
580580
} else {
581581
Some(opts.notify_chan.swap_unwrap())

src/libcore/unstable/extfmt.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ pub mod rt {
538538
pub fn conv_str(cv: Conv, s: &str, buf: &mut ~str) {
539539
// For strings, precision is the maximum characters
540540
// displayed
541-
let mut unpadded = match cv.precision {
541+
let unpadded = match cv.precision {
542542
CountImplied => s,
543543
CountIs(max) => if (max as uint) < str::char_len(s) {
544544
str::slice(s, 0, max as uint)
@@ -596,7 +596,7 @@ pub mod rt {
596596
#[deriving(Eq)]
597597
pub enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat }
598598
599-
pub fn pad(cv: Conv, mut s: &str, head: Option<char>, mode: PadMode,
599+
pub fn pad(cv: Conv, s: &str, head: Option<char>, mode: PadMode,
600600
buf: &mut ~str) {
601601
let headsize = match head { Some(_) => 1, _ => 0 };
602602
let uwidth : uint = match cv.width {

src/libcore/vec.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1755,7 +1755,7 @@ impl<T: TotalOrd> TotalOrd for @[T] {
17551755

17561756
fn lt<T:Ord>(a: &[T], b: &[T]) -> bool {
17571757
let (a_len, b_len) = (a.len(), b.len());
1758-
let mut end = uint::min(a_len, b_len);
1758+
let end = uint::min(a_len, b_len);
17591759

17601760
let mut i = 0;
17611761
while i < end {
@@ -3897,7 +3897,7 @@ mod tests {
38973897

38983898
#[test]
38993899
fn reversed_mut() {
3900-
let mut v2 = reversed::<int>(~[10, 20]);
3900+
let v2 = reversed::<int>(~[10, 20]);
39013901
assert!(v2[0] == 20);
39023902
assert!(v2[1] == 10);
39033903
}

src/librustc/back/link.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ pub mod write {
273273
let LLVMOptDefault = 2 as c_int; // -O2, -Os
274274
let LLVMOptAggressive = 3 as c_int; // -O3
275275

276-
let mut CodeGenOptLevel = match opts.optimize {
276+
let CodeGenOptLevel = match opts.optimize {
277277
session::No => LLVMOptNone,
278278
session::Less => LLVMOptLess,
279279
session::Default => LLVMOptDefault,
@@ -294,7 +294,7 @@ pub mod write {
294294
return;
295295
}
296296

297-
let mut FileType;
297+
let FileType;
298298
if output_type == output_type_object ||
299299
output_type == output_type_exe {
300300
FileType = lib::llvm::ObjectFile;
@@ -820,7 +820,7 @@ pub fn link_binary(sess: Session,
820820
cc_args.push(output.to_str());
821821
cc_args.push(obj_filename.to_str());
822822
823-
let mut lib_cmd;
823+
let lib_cmd;
824824
let os = sess.targ_cfg.os;
825825
if os == session::os_macos {
826826
lib_cmd = ~"-dynamiclib";

src/librustc/driver/driver.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ pub fn compile_upto(sess: Session, cfg: ast::crate_cfg,
349349
outputs: Option<@OutputFilenames>)
350350
-> (@ast::crate, Option<ty::ctxt>) {
351351
let time_passes = sess.time_passes();
352-
let mut crate = time(time_passes, ~"parsing",
352+
let crate = time(time_passes, ~"parsing",
353353
|| parse_input(sess, copy cfg, input) );
354354
if upto == cu_parse { return (crate, None); }
355355

src/librustc/metadata/encoder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1341,7 +1341,7 @@ pub static metadata_encoding_version : &'static [u8] =
13411341
13421342
pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] {
13431343
let wr = @io::BytesWriter();
1344-
let mut stats = Stats {
1344+
let stats = Stats {
13451345
inline_bytes: 0,
13461346
attr_bytes: 0,
13471347
dep_bytes: 0,

src/librustc/middle/borrowck/check_loans.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,18 @@ pub impl CheckLoanCtxt {
367367
// are only assigned once
368368
} else {
369369
match cmt.mutbl {
370-
McDeclared | McInherited => { /*ok*/ }
370+
McDeclared | McInherited => {
371+
// Ok, but if this loan is a mutable loan, then mark the
372+
// loan path (if it exists) as being used. This is similar
373+
// to the check performed in loan.rs in issue_loan(). This
374+
// type of use of mutable is different from issuing a loan,
375+
// however.
376+
for cmt.lp.each |lp| {
377+
for lp.node_id().each |&id| {
378+
self.tcx().used_mut_nodes.insert(id);
379+
}
380+
}
381+
}
371382
McReadOnly | McImmutable => {
372383
self.bccx.span_err(
373384
ex.span,

src/librustc/middle/borrowck/gather_loans.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ pub impl GatherLoanCtxt {
305305
let mcx = &mem_categorization_ctxt {
306306
tcx: self.tcx(),
307307
method_map: self.bccx.method_map};
308-
let mut cmt = mcx.cat_expr_autoderefd(expr, autoderefs);
308+
let cmt = mcx.cat_expr_autoderefd(expr, autoderefs);
309309
debug!("after autoderef, cmt=%s", self.bccx.cmt_to_repr(cmt));
310310

311311
match autoref.kind {

src/librustc/middle/borrowck/loan.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,17 @@ pub impl LoanContext {
274274
if !owns_lent_data ||
275275
self.bccx.is_subregion_of(self.scope_region, scope_ub)
276276
{
277-
if loan_kind.is_take() && !cmt.mutbl.is_mutable() {
277+
if cmt.mutbl.is_mutable() {
278+
// If this loan is a mutable loan, then mark the loan path (if
279+
// it exists) as being used. This is similar to the check
280+
// performed in check_loans.rs in check_assignment(), but this
281+
// is for a different purpose of having the 'mut' qualifier.
282+
for cmt.lp.each |lp| {
283+
for lp.node_id().each |&id| {
284+
self.tcx().used_mut_nodes.insert(id);
285+
}
286+
}
287+
} else if loan_kind.is_take() {
278288
// We do not allow non-mutable data to be "taken"
279289
// under any circumstances.
280290
return Err(bckerr {

src/librustc/middle/check_match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ pub fn specialize(cx: @MatchCheckCtxt,
481481
left_ty: ty::t)
482482
-> Option<~[@pat]> {
483483
// Sad, but I can't get rid of this easily
484-
let mut r0 = copy *raw_pat(r[0]);
484+
let r0 = copy *raw_pat(r[0]);
485485
match r0 {
486486
pat{id: pat_id, node: n, span: pat_span} =>
487487
match n {

src/librustc/middle/lint.rs

+57
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use core::prelude::*;
1313
use driver::session::Session;
1414
use driver::session;
1515
use middle::ty;
16+
use middle::pat_util;
1617
use util::ppaux::{ty_to_str};
1718

1819
use core::hashmap::HashMap;
@@ -86,6 +87,7 @@ pub enum lint {
8687

8788
unused_variable,
8889
dead_assignment,
90+
unused_mut,
8991
}
9092

9193
pub fn level_to_str(lv: level) -> &'static str {
@@ -277,6 +279,13 @@ pub fn get_lint_dict() -> LintDict {
277279
desc: "detect assignments that will never be read",
278280
default: warn
279281
}),
282+
283+
(~"unused_mut",
284+
LintSpec {
285+
lint: unused_mut,
286+
desc: "detect mut variables which don't need to be mutable",
287+
default: warn
288+
}),
280289
];
281290
let mut map = HashMap::new();
282291
do vec::consume(v) |_, (k, v)| {
@@ -499,6 +508,7 @@ fn check_item(i: @ast::item, cx: ty::ctxt) {
499508
check_item_deprecated_mutable_fields(cx, i);
500509
check_item_deprecated_drop(cx, i);
501510
check_item_unused_unsafe(cx, i);
511+
check_item_unused_mut(cx, i);
502512
}
503513

504514
// Take a visitor, and modify it so that it will not proceed past subitems.
@@ -954,6 +964,53 @@ fn check_item_unused_unsafe(cx: ty::ctxt, it: @ast::item) {
954964
visit::visit_item(it, (), visit);
955965
}
956966

967+
fn check_item_unused_mut(tcx: ty::ctxt, it: @ast::item) {
968+
let check_pat: @fn(@ast::pat) = |p| {
969+
let mut used = false;
970+
let mut bindings = 0;
971+
do pat_util::pat_bindings(tcx.def_map, p) |_, id, _, _| {
972+
used = used || tcx.used_mut_nodes.contains(&id);
973+
bindings += 1;
974+
}
975+
if !used {
976+
let msg = if bindings == 1 {
977+
~"variable does not need to be mutable"
978+
} else {
979+
~"variables do not need to be mutable"
980+
};
981+
tcx.sess.span_lint(unused_mut, p.id, it.id, p.span, msg);
982+
}
983+
};
984+
985+
let visit_fn_decl: @fn(&ast::fn_decl) = |fd| {
986+
for fd.inputs.each |arg| {
987+
if arg.is_mutbl {
988+
check_pat(arg.pat);
989+
}
990+
}
991+
};
992+
993+
let visit = item_stopping_visitor(
994+
visit::mk_simple_visitor(@visit::SimpleVisitor {
995+
visit_local: |l| {
996+
if l.node.is_mutbl {
997+
check_pat(l.node.pat);
998+
}
999+
},
1000+
visit_fn: |_, fd, _, _, _| visit_fn_decl(fd),
1001+
visit_ty_method: |tm| visit_fn_decl(&tm.decl),
1002+
visit_struct_method: |sm| visit_fn_decl(&sm.decl),
1003+
visit_trait_method: |tm| {
1004+
match *tm {
1005+
ast::required(ref tm) => visit_fn_decl(&tm.decl),
1006+
ast::provided(m) => visit_fn_decl(&m.decl),
1007+
}
1008+
},
1009+
.. *visit::default_simple_visitor()
1010+
}));
1011+
visit::visit_item(it, (), visit);
1012+
}
1013+
9571014
fn check_fn(tcx: ty::ctxt, fk: &visit::fn_kind, decl: &ast::fn_decl,
9581015
_body: &ast::blk, span: span, id: ast::node_id) {
9591016
debug!("lint check_fn fk=%? id=%?", fk, id);

0 commit comments

Comments
 (0)