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.
This commit is contained in:
bors 2013-04-22 15:36:51 -07:00
commit aba93c6b60
52 changed files with 265 additions and 120 deletions

View File

@ -121,7 +121,7 @@ fn test_with_ref() {
#[test]
fn test_with_mut_ref() {
let good = ~[1, 2, 3];
let mut v = ~[1, 2];
let v = ~[1, 2];
let c = Cell(v);
do c.with_mut_ref() |v| { v.push(3); }
let v = c.take();

View File

@ -67,7 +67,7 @@ pub fn deflate_bytes(bytes: &const [u8]) -> ~[u8] {
pub fn inflate_bytes(bytes: &const [u8]) -> ~[u8] {
do vec::as_const_buf(bytes) |b, len| {
unsafe {
let mut outsz : size_t = 0;
let outsz : size_t = 0;
let res =
rustrt::tinfl_decompress_mem_to_heap(b as *c_void,
len as size_t,

View File

@ -854,7 +854,7 @@ pub fn extract_unc_prefix(s: &str) -> Option<(~str,~str)> {
while i < s.len() {
if is_sep(s[i]) {
let pre = s.slice(2, i).to_owned();
let mut rest = s.slice(i, s.len()).to_owned();
let rest = s.slice(i, s.len()).to_owned();
return Some((pre, rest));
}
i += 1;

View File

@ -742,7 +742,7 @@ struct XorShiftState {
impl Rng for XorShiftState {
fn next(&self) -> u32 {
let x = self.x;
let mut t = x ^ (x << 11);
let t = x ^ (x << 11);
self.x = self.y;
self.y = self.z;
self.z = self.w;

View File

@ -210,7 +210,7 @@ fn visit_inner(&self, inner: *TyDesc) -> bool {
#[inline(always)]
fn visit_ptr_inner(&self, ptr: *c_void, inner: *TyDesc) -> bool {
unsafe {
let mut u = ReprVisitor(ptr, self.writer);
let u = ReprVisitor(ptr, self.writer);
let v = reflect::MovePtrAdaptor(u);
visit_tydesc(inner, @v as @TyVisitor);
true
@ -667,7 +667,7 @@ pub fn write_repr<T>(writer: @Writer, object: &T) {
unsafe {
let ptr = ptr::to_unsafe_ptr(object) as *c_void;
let tydesc = intrinsic::get_tydesc::<T>();
let mut u = ReprVisitor(ptr, writer);
let u = ReprVisitor(ptr, writer);
let v = reflect::MovePtrAdaptor(u);
visit_tydesc(tydesc, @v as @TyVisitor)
}

View File

@ -402,7 +402,7 @@ fn loop_smoke_test() {
fn idle_new_then_close() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let mut idle_watcher = { IdleWatcher::new(&mut loop_) };
let idle_watcher = { IdleWatcher::new(&mut loop_) };
idle_watcher.close();
}
}

View File

@ -393,7 +393,7 @@ fn connect_read() {
let buf = vec_from_uv_buf(buf);
rtdebug!("read cb!");
if status.is_none() {
let bytes = buf.unwrap();
let _bytes = buf.unwrap();
rtdebug!("%s", bytes.slice(0, nread as uint).to_str());
} else {
rtdebug!("status after read: %s", status.get().to_str());

View File

@ -206,7 +206,7 @@ fn listen(&mut self) -> Option<~StreamObject> {
let mut server_stream_watcher = server_stream_watcher;
let mut loop_ = loop_from_watcher(&server_stream_watcher);
let mut client_tcp_watcher = TcpWatcher::new(&mut loop_);
let mut client_tcp_watcher = client_tcp_watcher.as_stream();
let client_tcp_watcher = client_tcp_watcher.as_stream();
// XXX: Need's to be surfaced in interface
server_stream_watcher.accept(client_tcp_watcher);
Some(~UvStream::new(client_tcp_watcher))

View File

@ -343,7 +343,7 @@ fn finish(&mut self) -> int { finish_repr(&mut self.r) }
fn force_destroy(&mut self) { destroy_repr(&mut self.r, true); }
}
let mut repr = ProgRepr {
let repr = ProgRepr {
pid: pid,
in_fd: pipe_input.out,
out_file: os::fdopen(pipe_output.in),

View File

@ -673,7 +673,7 @@ pub fn levdistance(s: &str, t: &str) -> uint {
for t.each_chari |j, tc| {
let mut next = dcol[j + 1];
let next = dcol[j + 1];
if sc == tc {
dcol[j + 1] = current;
@ -909,7 +909,7 @@ fn cmp(&self, other: &@str) -> Ordering { cmp(*self, *other) }
/// Bytewise slice less than
fn lt(a: &str, b: &str) -> bool {
let (a_len, b_len) = (a.len(), b.len());
let mut end = uint::min(a_len, b_len);
let end = uint::min(a_len, b_len);
let mut i = 0;
while i < end {
@ -1715,7 +1715,7 @@ pub fn utf16_chars(v: &[u16], f: &fn(char)) {
let len = vec::len(v);
let mut i = 0u;
while (i < len && v[i] != 0u16) {
let mut u = v[i];
let u = v[i];
if u <= 0xD7FF_u16 || u >= 0xE000_u16 {
f(u as char);

View File

@ -575,7 +575,7 @@ fn spawn_raw_oldsched(opts: TaskOpts, f: ~fn()) {
};
assert!(!new_task.is_null());
// Getting killed after here would leak the task.
let mut notify_chan = if opts.notify_chan.is_none() {
let notify_chan = if opts.notify_chan.is_none() {
None
} else {
Some(opts.notify_chan.swap_unwrap())

View File

@ -538,7 +538,7 @@ pub fn conv_char(cv: Conv, c: char, buf: &mut ~str) {
pub fn conv_str(cv: Conv, s: &str, buf: &mut ~str) {
// For strings, precision is the maximum characters
// displayed
let mut unpadded = match cv.precision {
let unpadded = match cv.precision {
CountImplied => s,
CountIs(max) => if (max as uint) < str::char_len(s) {
str::slice(s, 0, max as uint)
@ -596,7 +596,7 @@ pub fn get_int_precision(cv: Conv) -> uint {
#[deriving(Eq)]
pub enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat }
pub fn pad(cv: Conv, mut s: &str, head: Option<char>, mode: PadMode,
pub fn pad(cv: Conv, s: &str, head: Option<char>, mode: PadMode,
buf: &mut ~str) {
let headsize = match head { Some(_) => 1, _ => 0 };
let uwidth : uint = match cv.width {

View File

@ -1755,7 +1755,7 @@ fn cmp(&self, other: &@[T]) -> Ordering { cmp(*self, *other) }
fn lt<T:Ord>(a: &[T], b: &[T]) -> bool {
let (a_len, b_len) = (a.len(), b.len());
let mut end = uint::min(a_len, b_len);
let end = uint::min(a_len, b_len);
let mut i = 0;
while i < end {
@ -3897,7 +3897,7 @@ fn reverse_and_reversed() {
#[test]
fn reversed_mut() {
let mut v2 = reversed::<int>(~[10, 20]);
let v2 = reversed::<int>(~[10, 20]);
assert!(v2[0] == 20);
assert!(v2[1] == 10);
}

View File

@ -273,7 +273,7 @@ pub fn run_passes(sess: Session,
let LLVMOptDefault = 2 as c_int; // -O2, -Os
let LLVMOptAggressive = 3 as c_int; // -O3
let mut CodeGenOptLevel = match opts.optimize {
let CodeGenOptLevel = match opts.optimize {
session::No => LLVMOptNone,
session::Less => LLVMOptLess,
session::Default => LLVMOptDefault,
@ -294,7 +294,7 @@ pub fn run_passes(sess: Session,
return;
}
let mut FileType;
let FileType;
if output_type == output_type_object ||
output_type == output_type_exe {
FileType = lib::llvm::ObjectFile;
@ -820,7 +820,7 @@ fn unlib(config: @session::config, stem: ~str) -> ~str {
cc_args.push(output.to_str());
cc_args.push(obj_filename.to_str());
let mut lib_cmd;
let lib_cmd;
let os = sess.targ_cfg.os;
if os == session::os_macos {
lib_cmd = ~"-dynamiclib";

View File

@ -349,7 +349,7 @@ pub fn compile_upto(sess: Session, cfg: ast::crate_cfg,
outputs: Option<@OutputFilenames>)
-> (@ast::crate, Option<ty::ctxt>) {
let time_passes = sess.time_passes();
let mut crate = time(time_passes, ~"parsing",
let crate = time(time_passes, ~"parsing",
|| parse_input(sess, copy cfg, input) );
if upto == cu_parse { return (crate, None); }

View File

@ -1341,7 +1341,7 @@ fn encode_hash(ebml_w: &writer::Encoder, hash: &str) {
pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] {
let wr = @io::BytesWriter();
let mut stats = Stats {
let stats = Stats {
inline_bytes: 0,
attr_bytes: 0,
dep_bytes: 0,

View File

@ -367,7 +367,18 @@ fn check_assignment(&mut self, at: assignment_type, ex: @ast::expr) {
// are only assigned once
} else {
match cmt.mutbl {
McDeclared | McInherited => { /*ok*/ }
McDeclared | McInherited => {
// Ok, but if this loan is a mutable loan, then mark the
// loan path (if it exists) as being used. This is similar
// to the check performed in loan.rs in issue_loan(). This
// type of use of mutable is different from issuing a loan,
// however.
for cmt.lp.each |lp| {
for lp.node_id().each |&id| {
self.tcx().used_mut_nodes.insert(id);
}
}
}
McReadOnly | McImmutable => {
self.bccx.span_err(
ex.span,

View File

@ -305,7 +305,7 @@ fn guarantee_adjustments(&mut self,
let mcx = &mem_categorization_ctxt {
tcx: self.tcx(),
method_map: self.bccx.method_map};
let mut cmt = mcx.cat_expr_autoderefd(expr, autoderefs);
let cmt = mcx.cat_expr_autoderefd(expr, autoderefs);
debug!("after autoderef, cmt=%s", self.bccx.cmt_to_repr(cmt));
match autoref.kind {

View File

@ -274,7 +274,17 @@ fn issue_loan(&mut self,
if !owns_lent_data ||
self.bccx.is_subregion_of(self.scope_region, scope_ub)
{
if loan_kind.is_take() && !cmt.mutbl.is_mutable() {
if cmt.mutbl.is_mutable() {
// If this loan is a mutable loan, then mark the loan path (if
// it exists) as being used. This is similar to the check
// performed in check_loans.rs in check_assignment(), but this
// is for a different purpose of having the 'mut' qualifier.
for cmt.lp.each |lp| {
for lp.node_id().each |&id| {
self.tcx().used_mut_nodes.insert(id);
}
}
} else if loan_kind.is_take() {
// We do not allow non-mutable data to be "taken"
// under any circumstances.
return Err(bckerr {

View File

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

View File

@ -13,6 +13,7 @@
use driver::session::Session;
use driver::session;
use middle::ty;
use middle::pat_util;
use util::ppaux::{ty_to_str};
use core::hashmap::HashMap;
@ -86,6 +87,7 @@ pub enum lint {
unused_variable,
dead_assignment,
unused_mut,
}
pub fn level_to_str(lv: level) -> &'static str {
@ -277,6 +279,13 @@ pub fn get_lint_dict() -> LintDict {
desc: "detect assignments that will never be read",
default: warn
}),
(~"unused_mut",
LintSpec {
lint: unused_mut,
desc: "detect mut variables which don't need to be mutable",
default: warn
}),
];
let mut map = HashMap::new();
do vec::consume(v) |_, (k, v)| {
@ -499,6 +508,7 @@ fn check_item(i: @ast::item, cx: ty::ctxt) {
check_item_deprecated_mutable_fields(cx, i);
check_item_deprecated_drop(cx, i);
check_item_unused_unsafe(cx, i);
check_item_unused_mut(cx, i);
}
// 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) {
visit::visit_item(it, (), visit);
}
fn check_item_unused_mut(tcx: ty::ctxt, it: @ast::item) {
let check_pat: @fn(@ast::pat) = |p| {
let mut used = false;
let mut bindings = 0;
do pat_util::pat_bindings(tcx.def_map, p) |_, id, _, _| {
used = used || tcx.used_mut_nodes.contains(&id);
bindings += 1;
}
if !used {
let msg = if bindings == 1 {
~"variable does not need to be mutable"
} else {
~"variables do not need to be mutable"
};
tcx.sess.span_lint(unused_mut, p.id, it.id, p.span, msg);
}
};
let visit_fn_decl: @fn(&ast::fn_decl) = |fd| {
for fd.inputs.each |arg| {
if arg.is_mutbl {
check_pat(arg.pat);
}
}
};
let visit = item_stopping_visitor(
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_local: |l| {
if l.node.is_mutbl {
check_pat(l.node.pat);
}
},
visit_fn: |_, fd, _, _, _| visit_fn_decl(fd),
visit_ty_method: |tm| visit_fn_decl(&tm.decl),
visit_struct_method: |sm| visit_fn_decl(&sm.decl),
visit_trait_method: |tm| {
match *tm {
ast::required(ref tm) => visit_fn_decl(&tm.decl),
ast::provided(m) => visit_fn_decl(&m.decl),
}
},
.. *visit::default_simple_visitor()
}));
visit::visit_item(it, (), visit);
}
fn check_fn(tcx: ty::ctxt, fk: &visit::fn_kind, decl: &ast::fn_decl,
_body: &ast::blk, span: span, id: ast::node_id) {
debug!("lint check_fn fk=%? id=%?", fk, id);

View File

@ -1516,9 +1516,8 @@ fn check_local(local: @local, self: @Liveness, vt: vt<@Liveness>) {
// Initializer:
self.warn_about_unused_or_dead_vars_in_pat(local.node.pat);
if !local.node.is_mutbl {
self.check_for_reassignments_in_pat(local.node.pat);
}
self.check_for_reassignments_in_pat(local.node.pat,
local.node.is_mutbl);
}
None => {
@ -1702,12 +1701,15 @@ fn check_lvalue(@self, expr: @expr, vt: vt<@Liveness>) {
match expr.node {
expr_path(_) => {
match *self.tcx.def_map.get(&expr.id) {
def_local(nid, false) => {
// Assignment to an immutable variable or argument:
// only legal if there is no later assignment.
def_local(nid, mutbl) => {
// Assignment to an immutable variable or argument: only legal
// if there is no later assignment. If this local is actually
// mutable, then check for a reassignment to flag the mutability
// as being used.
let ln = self.live_node(expr.id, expr.span);
let var = self.variable(nid, expr.span);
self.check_for_reassignment(ln, var, expr.span);
self.check_for_reassignment(ln, var, expr.span,
if mutbl {Some(nid)} else {None});
self.warn_about_dead_assign(expr.span, expr.id, ln, var);
}
def => {
@ -1731,23 +1733,28 @@ fn check_lvalue(@self, expr: @expr, vt: vt<@Liveness>) {
}
}
fn check_for_reassignments_in_pat(@self, pat: @pat) {
do self.pat_bindings(pat) |ln, var, sp, _id| {
self.check_for_reassignment(ln, var, sp);
fn check_for_reassignments_in_pat(@self, pat: @pat, mutbl: bool) {
do self.pat_bindings(pat) |ln, var, sp, id| {
self.check_for_reassignment(ln, var, sp,
if mutbl {Some(id)} else {None});
}
}
fn check_for_reassignment(@self, ln: LiveNode, var: Variable,
orig_span: span) {
orig_span: span, mutbl: Option<node_id>) {
match self.assigned_on_exit(ln, var) {
Some(ExprNode(span)) => {
self.tcx.sess.span_err(
span,
~"re-assignment of immutable variable");
self.tcx.sess.span_note(
orig_span,
~"prior assignment occurs here");
match mutbl {
Some(id) => { self.tcx.used_mut_nodes.insert(id); }
None => {
self.tcx.sess.span_err(
span,
~"re-assignment of immutable variable");
self.tcx.sess.span_note(
orig_span,
~"prior assignment occurs here");
}
}
}
Some(lnk) => {
self.tcx.sess.span_bug(

View File

@ -351,6 +351,16 @@ fn to_user_str(&self) -> ~str {
}
}
pub impl loan_path {
fn node_id(&self) -> Option<ast::node_id> {
match *self {
lp_local(id) | lp_arg(id) => Some(id),
lp_deref(lp, _) | lp_comp(lp, _) => lp.node_id(),
lp_self => None
}
}
}
pub impl mem_categorization_ctxt {
fn cat_expr(&self, expr: @ast::expr) -> cmt {
match self.tcx.adjustments.find(&expr.id) {

View File

@ -960,7 +960,7 @@ fn add_child(@mut self,
// child name directly. Otherwise, we create or reuse an anonymous
// module and add the child to that.
let mut module_;
let module_;
match reduced_graph_parent {
ModuleReducedGraphParent(parent_module) => {
module_ = parent_module;
@ -1527,7 +1527,7 @@ fn build_reduced_graph_for_block(@mut self,
block: &blk,
parent: ReducedGraphParent,
visitor: vt<ReducedGraphParent>) {
let mut new_parent;
let new_parent;
if self.block_needs_anonymous_module(block) {
let block_id = block.node.id;
@ -2427,7 +2427,7 @@ fn resolve_glob_import(@mut self,
let merge_import_resolution = |ident,
name_bindings: @mut NameBindings| {
let mut dest_import_resolution;
let dest_import_resolution;
match module_.import_resolutions.find(ident) {
None => {
// Create a new import resolution from this child.
@ -2583,8 +2583,8 @@ fn resolve_module_path_for_import(@mut self,
let module_prefix_result = self.resolve_module_prefix(module_,
module_path);
let mut search_module;
let mut start_index;
let search_module;
let start_index;
match module_prefix_result {
Failed => {
self.session.span_err(span, ~"unresolved name");
@ -3221,7 +3221,7 @@ fn upvarify(@mut self,
allow_capturing_self: AllowCapturingSelfFlag)
-> Option<def_like> {
let mut def;
let mut is_ty_param;
let is_ty_param;
match def_like {
dl_def(d @ def_local(*)) | dl_def(d @ def_upvar(*)) |
@ -4530,7 +4530,7 @@ fn resolve_module_relative_path(@mut self,
-> Option<def> {
let module_path_idents = self.intern_module_part_of_path(path);
let mut containing_module;
let containing_module;
match self.resolve_module_path_for_import(self.current_module,
module_path_idents,
UseLexicalScope,
@ -4578,7 +4578,7 @@ fn resolve_crate_relative_path(@mut self,
let root_module = self.graph_root.get_module();
let mut containing_module;
let containing_module;
match self.resolve_module_path_from_root(root_module,
module_path_idents,
0,
@ -4622,7 +4622,7 @@ fn resolve_identifier_in_local_ribs(@mut self,
span: span)
-> Option<def> {
// Check the local set of ribs.
let mut search_result;
let search_result;
match namespace {
ValueNS => {
search_result = self.search_ribs(&mut self.value_ribs, ident,

View File

@ -248,7 +248,7 @@ pub enum opt_result {
pub fn trans_opt(bcx: block, o: &Opt) -> opt_result {
let _icx = bcx.insn_ctxt("match::trans_opt");
let ccx = bcx.ccx();
let mut bcx = bcx;
let bcx = bcx;
match *o {
lit(ExprLit(lit_expr)) => {
let datumblock = expr::trans_to_datum(bcx, lit_expr);

View File

@ -292,7 +292,7 @@ pub fn trans_fn_ref_with_vtables(
}
// Find the actual function pointer.
let mut val = {
let val = {
if def_id.crate == ast::local_crate {
// Internal reference.
get_item_val(ccx, def_id.node)
@ -415,7 +415,7 @@ pub fn trans_lang_call_with_type_params(bcx: block,
type_params,
None,
fty);
let mut llfnty = type_of::type_of(callee.bcx.ccx(),
let llfnty = type_of::type_of(callee.bcx.ccx(),
substituted);
new_llval = PointerCast(callee.bcx, fn_data.llfn, llfnty);
}
@ -712,7 +712,7 @@ pub fn trans_arg_expr(bcx: block,
}
};
let mut arg_datum = arg_datumblock.datum;
let mut bcx = arg_datumblock.bcx;
let bcx = arg_datumblock.bcx;
debug!(" arg datum: %s", arg_datum.to_str(bcx.ccx()));

View File

@ -261,7 +261,7 @@ pub fn build_closure(bcx0: block,
include_ret_handle: Option<ValueRef>) -> ClosureResult {
let _icx = bcx0.insn_ctxt("closure::build_closure");
// If we need to, package up the iterator body to call
let mut bcx = bcx0;;
let bcx = bcx0;;
let ccx = bcx.ccx(), tcx = ccx.tcx;
// Package up the captured upvars

View File

@ -192,7 +192,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
}
Some(&@AutoAddEnv(*)) => {
let mut bcx = bcx;
let mut datum = unpack_datum!(bcx, {
let datum = unpack_datum!(bcx, {
trans_to_datum_unadjusted(bcx, expr)
});
add_env(bcx, expr, datum)
@ -1187,7 +1187,7 @@ fn trans_rec_or_struct(bcx: block,
dest: Dest) -> block
{
let _icx = bcx.insn_ctxt("trans_rec");
let mut bcx = bcx;
let bcx = bcx;
let ty = node_id_type(bcx, id);
let tcx = bcx.tcx();
@ -1505,7 +1505,7 @@ fn trans_lazy_binop(bcx: block,
b: @ast::expr) -> DatumBlock {
let _icx = bcx.insn_ctxt("trans_lazy_binop");
let binop_ty = expr_ty(bcx, binop_expr);
let mut bcx = bcx;
let bcx = bcx;
let Result {bcx: past_lhs, val: lhs} = {
do base::with_scope_result(bcx, a.info(), ~"lhs") |bcx| {

View File

@ -567,7 +567,8 @@ pub fn trans_intrinsic(ccx: @CrateContext,
set_fixed_stack_segment(fcx.llfn);
}
let mut bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
let mut bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
match *ccx.sess.str_of(item.ident) {
~"atomic_cxchg" => {
let old = AtomicCmpXchg(bcx,

View File

@ -102,7 +102,7 @@ pub fn monomorphic_fn(ccx: @CrateContext,
}
let tpt = ty::lookup_item_type(ccx.tcx, fn_id);
let mut llitem_ty = tpt.ty;
let llitem_ty = tpt.ty;
let map_node = session::expect(ccx.sess, ccx.tcx.items.find(&fn_id.node),
|| fmt!("While monomorphizing %?, couldn't find it in the item map \

View File

@ -304,6 +304,11 @@ struct ctxt_ {
// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
// present in this set can be warned about.
used_unsafe: @mut HashSet<ast::node_id>,
// Set of nodes which mark locals as mutable which end up getting used at
// some point. Local variable definitions not in this set can be warned
// about.
used_mut_nodes: @mut HashSet<ast::node_id>,
}
pub enum tbox_flag {
@ -933,6 +938,7 @@ pub fn mk_ctxt(s: session::Session,
destructors: @mut HashSet::new(),
trait_impls: @mut HashMap::new(),
used_unsafe: @mut HashSet::new(),
used_mut_nodes: @mut HashSet::new(),
}
}

View File

@ -180,7 +180,7 @@ pub struct Candidate {
pub impl<'self> LookupContext<'self> {
fn do_lookup(&self, self_ty: ty::t) -> Option<method_map_entry> {
let mut self_ty = structurally_resolved_type(self.fcx,
let self_ty = structurally_resolved_type(self.fcx,
self.self_expr.span,
self_ty);

View File

@ -1625,7 +1625,7 @@ fn check_expr_fn(fcx: @mut FnCtxt,
// block syntax lambdas; that is, lambdas without explicit
// sigils.
let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
let mut error_happened = false;
let error_happened = false;
let (expected_sig,
expected_purity,
expected_sigil,
@ -1706,7 +1706,7 @@ fn check_field(fcx: @mut FnCtxt,
field: ast::ident,
tys: &[@ast::Ty]) {
let tcx = fcx.ccx.tcx;
let mut bot = check_expr(fcx, base);
let bot = check_expr(fcx, base);
let expr_t = structurally_resolved_type(fcx, expr.span,
fcx.expr_ty(base));
let (base_t, derefs) = do_autoderef(fcx, expr.span, expr_t);
@ -2867,7 +2867,7 @@ pub fn check_decl_local(fcx: @mut FnCtxt, local: @ast::local) {
}
pub fn check_stmt(fcx: @mut FnCtxt, stmt: @ast::stmt) {
let mut node_id;
let node_id;
let mut saw_bot = false;
let mut saw_err = false;
match stmt.node {
@ -3124,7 +3124,8 @@ fn do_check(ccx: @mut CrateCtxt,
ccx.tcx.enum_var_cache.insert(local_def(id), @variants);
// Check that it is possible to represent this enum:
let mut outer = true, did = local_def(id);
let mut outer = true;
let did = local_def(id);
if ty::type_structurally_contains(ccx.tcx, rty, |sty| {
match *sty {
ty::ty_enum(id, _) if id == did => {

View File

@ -11,7 +11,7 @@
use core::prelude::*;
use middle::resolve::Impl;
use middle::ty::{param_ty};
use middle::ty::param_ty;
use middle::ty;
use middle::typeck::check::{FnCtxt, impl_self_ty};
use middle::typeck::check::{structurally_resolved_type};

View File

@ -158,7 +158,7 @@ pub fn new(self_ty: ast::self_ty_,
variance: Option<ty::region_variance>,
rcvr_generics: &ast::Generics)
-> MethodRscope {
let mut region_param_names =
let region_param_names =
RegionParamNames::from_generics(rcvr_generics);
MethodRscope {
self_ty: self_ty,

View File

@ -891,7 +891,7 @@ fn test_to_str() {
#[test]
fn test_0_elements() {
let mut act;
let mut exp;
let exp;
act = Bitv::new(0u, false);
exp = vec::from_elem::<uint>(0u, 0u);
assert!(act.eq_vec(exp));

View File

@ -113,7 +113,7 @@ fn eachi(&self, f: &fn(uint, &T) -> bool) {
///
/// Fails if the deque is empty
fn pop_front(&mut self) -> T {
let mut result = self.elts[self.lo].swap_unwrap();
let result = self.elts[self.lo].swap_unwrap();
self.lo = (self.lo + 1u) % self.elts.len();
self.nelts -= 1u;
result
@ -126,7 +126,7 @@ fn pop_back(&mut self) -> T {
if self.hi == 0u {
self.hi = self.elts.len() - 1u;
} else { self.hi -= 1u; }
let mut result = self.elts[self.hi].swap_unwrap();
let result = self.elts[self.hi].swap_unwrap();
self.elts[self.hi] = None;
self.nelts -= 1u;
result
@ -204,7 +204,7 @@ fn eachi(&self, f: &fn(uint, &T) -> bool) {
///
/// Fails if the deque is empty
fn pop_front(&mut self) -> T {
let mut result = self.elts[self.lo].swap_unwrap();
let result = self.elts[self.lo].swap_unwrap();
self.lo = (self.lo + 1u) % self.elts.len();
self.nelts -= 1u;
result
@ -217,7 +217,7 @@ fn pop_back(&mut self) -> T {
if self.hi == 0u {
self.hi = self.elts.len() - 1u;
} else { self.hi -= 1u; }
let mut result = self.elts[self.hi].swap_unwrap();
let result = self.elts[self.hi].swap_unwrap();
self.elts[self.hi] = None;
self.nelts -= 1u;
result

View File

@ -220,7 +220,7 @@ fn push_head(@mut self, data: T) {
* node. O(1).
*/
fn push_head_n(@mut self, data: T) -> @mut DListNode<T> {
let mut nobe = DList::new_link(data);
let nobe = DList::new_link(data);
self.add_head(nobe);
nobe.get()
}
@ -233,7 +233,7 @@ fn push(@mut self, data: T) {
* node. O(1).
*/
fn push_n(@mut self, data: T) -> @mut DListNode<T> {
let mut nobe = DList::new_link(data);
let nobe = DList::new_link(data);
self.add_tail(nobe);
nobe.get()
}
@ -263,7 +263,7 @@ fn insert_before_n(
data: T,
neighbour: @mut DListNode<T>
) -> @mut DListNode<T> {
let mut nobe = DList::new_link(data);
let nobe = DList::new_link(data);
self.insert_left(nobe, neighbour);
nobe.get()
}
@ -293,7 +293,7 @@ fn insert_after_n(
data: T,
neighbour: @mut DListNode<T>
) -> @mut DListNode<T> {
let mut nobe = DList::new_link(data);
let nobe = DList::new_link(data);
self.insert_right(neighbour, nobe);
nobe.get()
}

View File

@ -60,7 +60,7 @@ pub fn new(numer: T, denom: T) -> Ratio<T> {
/// Put self into lowest terms, with denom > 0.
fn reduce(&mut self) {
let mut g : T = gcd(self.numer, self.denom);
let g : T = gcd(self.numer, self.denom);
self.numer /= g;
self.denom /= g;
@ -505,4 +505,4 @@ fn test(s: &str) {
test(s);
}
}
}
}

View File

@ -838,8 +838,7 @@ pub fn serialize_node(node: @Node) -> ~str {
option::None => break,
option::Some(x) => {
//FIXME (#2744): Replace with memcpy or something similar
let mut local_buf: ~[u8] =
cast::transmute(*x.content);
let local_buf: ~[u8] = cast::transmute(*x.content);
let mut i = x.byte_offset;
while i < x.byte_len {
buf[offset] = local_buf[i];
@ -1156,7 +1155,7 @@ pub struct T {
}
pub fn empty() -> T {
let mut stack : ~[@Node] = ~[];
let stack : ~[@Node] = ~[];
T { stack: stack, stackpos: -1 }
}

View File

@ -93,7 +93,7 @@ fn process_msg_block(st: &mut Sha1State) {
assert!((vec::len(st.h) == digest_buf_len));
assert!((vec::uniq_len(st.work_buf) == work_buf_len));
let mut t: int; // Loop counter
let mut w = st.work_buf;
let w = st.work_buf;
// Initialize the first 16 words of the vector w
t = 0;
@ -260,7 +260,7 @@ fn result_str(&mut self) -> ~str {
return s;
}
}
let mut st = Sha1State {
let st = Sha1State {
h: vec::from_elem(digest_buf_len, 0u32),
len_low: 0u32,
len_high: 0u32,

View File

@ -239,7 +239,7 @@ fn binarysort<T:Copy + Ord>(array: &mut [T], start: uint) {
}
}
assert!(left == right);
let mut n = start-left;
let n = start-left;
copy_vec(array, left+1, array, left, n);
array[left] = pivot;
@ -416,7 +416,7 @@ fn push_run(&mut self, run_base: uint, run_len: uint) {
}
fn merge_at(&mut self, n: uint, array: &mut [T]) {
let mut size = self.runs.len();
let size = self.runs.len();
assert!(size >= 2);
assert!(n == size-2 || n == size-3);

View File

@ -427,8 +427,7 @@ fn run_tests(opts: &TestOpts,
let filtered_descs = filtered_tests.map(|t| t.desc);
callback(TeFiltered(filtered_descs));
let mut (filtered_tests,
filtered_benchs) =
let (filtered_tests, filtered_benchs) =
do vec::partition(filtered_tests) |e| {
match e.testfn {
StaticTestFn(_) | DynTestFn(_) => true,

View File

@ -147,7 +147,7 @@ pub fn empty_tm() -> Tm {
/// Returns the specified time in UTC
pub fn at_utc(clock: Timespec) -> Tm {
unsafe {
let mut Timespec { sec, nsec } = clock;
let Timespec { sec, nsec } = clock;
let mut tm = empty_tm();
rustrt::rust_gmtime(sec, nsec, &mut tm);
tm
@ -162,7 +162,7 @@ pub fn now_utc() -> Tm {
/// Returns the specified time in the local timezone
pub fn at(clock: Timespec) -> Tm {
unsafe {
let mut Timespec { sec, nsec } = clock;
let Timespec { sec, nsec } = clock;
let mut tm = empty_tm();
rustrt::rust_localtime(sec, nsec, &mut tm);
tm

View File

@ -342,7 +342,7 @@ fn highlight_lines_internal(cm: @codemap::CodeMap,
while num > 0u { num /= 10u; digits += 1u; }
// indent past |name:## | and the 0-offset column location
let mut left = str::len(fm.name) + digits + lo.col.to_uint() + 3u;
let left = str::len(fm.name) + digits + lo.col.to_uint() + 3u;
let mut s = ~"";
// Skip is the number of characters we need to skip because they are
// part of the 'filename:line ' part of the previous line.

View File

@ -96,7 +96,7 @@ fn make_count(cx: @ext_ctxt, sp: span, cnt: Count) -> @ast::expr {
}
}
fn make_ty(cx: @ext_ctxt, sp: span, t: Ty) -> @ast::expr {
let mut rt_type;
let rt_type;
match t {
TyHex(c) => match c {
CaseUpper => rt_type = ~"TyHexUpper",
@ -272,6 +272,7 @@ fn log_conv(c: &Conv) {
/* Translate each piece (portion of the fmt expression) by invoking the
corresponding function in core::unstable::extfmt. Each function takes a
buffer to insert data into along with the data being formatted. */
let npieces = pieces.len();
do vec::consume(pieces) |i, pc| {
match pc {
/* Raw strings get appended via str::push_str */
@ -279,9 +280,10 @@ fn log_conv(c: &Conv) {
let portion = mk_uniq_str(cx, fmt_sp, s);
/* If this is the first portion, then initialize the local
buffer with it directly */
buffer with it directly. If it's actually the only piece,
then there's no need for it to be mutable */
if i == 0 {
stms.push(mk_local(cx, fmt_sp, true, ident, portion));
stms.push(mk_local(cx, fmt_sp, npieces > 1, ident, portion));
} else {
let args = ~[mk_mut_addr_of(cx, fmt_sp, buf()), portion];
let call = mk_call_global(cx,

View File

@ -73,7 +73,7 @@ fn parse_attribute_naked(&self, style: ast::attr_style, lo: BytePos) ->
self.expect(&token::LBRACKET);
let meta_item = self.parse_meta_item();
self.expect(&token::RBRACKET);
let mut hi = self.span.hi;
let hi = self.span.hi;
return spanned(lo, hi, ast::attribute_ { style: style,
value: meta_item,
is_sugared_doc: false });
@ -141,16 +141,16 @@ fn parse_meta_item(&self) -> @ast::meta_item {
token::EQ => {
self.bump();
let lit = self.parse_lit();
let mut hi = self.span.hi;
let hi = self.span.hi;
@spanned(lo, hi, ast::meta_name_value(name, lit))
}
token::LPAREN => {
let inner_items = self.parse_meta_seq();
let mut hi = self.span.hi;
let hi = self.span.hi;
@spanned(lo, hi, ast::meta_list(name, inner_items))
}
_ => {
let mut hi = self.span.hi;
let hi = self.span.hi;
@spanned(lo, hi, ast::meta_word(name))
}
}

View File

@ -229,7 +229,7 @@ fn read_block_comment(rdr: @mut StringReader,
debug!(">>> block comment");
let p = rdr.last_pos;
let mut lines: ~[~str] = ~[];
let mut col: CharPos = rdr.col;
let col: CharPos = rdr.col;
bump(rdr);
bump(rdr);

View File

@ -810,7 +810,7 @@ fn is_named_argument(&self) -> bool {
// This version of parse arg doesn't necessarily require
// identifier names.
fn parse_arg_general(&self, require_name: bool) -> arg {
let mut m;
let m;
let mut is_mutbl = false;
let pat = if require_name || self.is_named_argument() {
m = self.parse_arg_mode();
@ -1154,7 +1154,7 @@ fn parse_bottom_expr(&self) -> @expr {
let lo = self.span.lo;
let mut hi = self.span.hi;
let mut ex: expr_;
let ex: expr_;
if *self.token == token::LPAREN {
self.bump();
@ -1629,9 +1629,9 @@ fn parse_matcher(&self, name_idx: @mut uint) -> matcher {
// parse a prefix-operator expr
fn parse_prefix_expr(&self) -> @expr {
let lo = self.span.lo;
let mut hi;
let hi;
let mut ex;
let ex;
match *self.token {
token::NOT => {
self.bump();
@ -1781,7 +1781,7 @@ fn parse_assign_expr(&self) -> @expr {
token::BINOPEQ(op) => {
self.bump();
let rhs = self.parse_expr();
let mut aop;
let aop;
match op {
token::PLUS => aop = add,
token::MINUS => aop = subtract,
@ -1956,7 +1956,7 @@ fn parse_while_expr(&self) -> @expr {
let lo = self.last_span.lo;
let cond = self.parse_expr();
let body = self.parse_block_no_value();
let mut hi = body.span.hi;
let hi = body.span.hi;
return self.mk_expr(lo, hi, expr_while(cond, body));
}
@ -1984,7 +1984,7 @@ fn parse_loop_expr(&self) -> @expr {
let lo = self.last_span.lo;
let body = self.parse_block_no_value();
let mut hi = body.span.hi;
let hi = body.span.hi;
return self.mk_expr(lo, hi, expr_loop(body, opt_ident));
} else {
// This is a 'continue' expression
@ -2043,7 +2043,7 @@ fn parse_match_expr(&self) -> @expr {
arms.push(ast::arm { pats: pats, guard: guard, body: blk });
}
let mut hi = self.span.hi;
let hi = self.span.hi;
self.bump();
return self.mk_expr(lo, hi, expr_match(discriminant, arms));
}
@ -2162,7 +2162,7 @@ fn parse_pat_fields(&self, refutable: bool) -> (~[ast::field_pat], bool) {
let hi1 = self.last_span.lo;
let fieldpath = ast_util::ident_to_path(mk_sp(lo1, hi1),
fieldname);
let mut subpat;
let subpat;
if *self.token == token::COLON {
self.bump();
subpat = self.parse_pat(refutable);
@ -2183,7 +2183,7 @@ fn parse_pat(&self, refutable: bool) -> @pat {
let lo = self.span.lo;
let mut hi = self.span.hi;
let mut pat;
let pat;
match *self.token {
token::UNDERSCORE => { self.bump(); pat = pat_wild; }
token::AT => {
@ -2534,7 +2534,7 @@ fn check_expected_item(p: &Parser, current_attrs: &[attribute]) {
match self.parse_item_or_view_item(/*bad*/ copy item_attrs,
true, false, false) {
iovi_item(i) => {
let mut hi = i.span.hi;
let hi = i.span.hi;
let decl = @spanned(lo, hi, decl_item(i));
return @spanned(lo, hi, stmt_decl(decl, self.get_id()));
}
@ -2704,7 +2704,7 @@ fn parse_block_tail_(&self, lo: BytePos, s: blk_check_mode,
}
}
}
let mut hi = self.span.hi;
let hi = self.span.hi;
self.bump();
let bloc = ast::blk_ {
view_items: view_items,
@ -3590,7 +3590,7 @@ fn parse_item_foreign_fn(&self, attrs: ~[attribute]) -> @foreign_item {
let purity = self.parse_fn_purity();
let (ident, generics) = self.parse_fn_header();
let decl = self.parse_fn_decl(|p| p.parse_arg());
let mut hi = self.span.hi;
let hi = self.span.hi;
self.expect(&token::SEMI);
@ast::foreign_item { ident: ident,
attrs: attrs,
@ -3798,7 +3798,7 @@ fn parse_struct_def(&self) -> @struct_def {
}
}
self.bump();
let mut actual_dtor = do the_dtor.map |dtor| {
let actual_dtor = do the_dtor.map |dtor| {
let (d_body, d_attrs, d_s) = copy *dtor;
codemap::spanned { node: ast::struct_dtor_ { id: self.get_id(),
attrs: d_attrs,

View File

@ -146,9 +146,9 @@ pub fn mk_printer(out: @io::Writer, linewidth: uint) -> @mut Printer {
// fall behind.
let n: uint = 3 * linewidth;
debug!("mk_printer %u", linewidth);
let mut token: ~[token] = vec::from_elem(n, EOF);
let mut size: ~[int] = vec::from_elem(n, 0);
let mut scan_stack: ~[uint] = vec::from_elem(n, 0u);
let token: ~[token] = vec::from_elem(n, EOF);
let size: ~[int] = vec::from_elem(n, 0);
let scan_stack: ~[uint] = vec::from_elem(n, 0u);
@mut Printer {
out: @out,
buf_len: n,

View File

@ -1972,7 +1972,7 @@ pub fn print_ty_fn(s: @ps,
pub fn maybe_print_trailing_comment(s: @ps, span: codemap::span,
next_pos: Option<BytePos>) {
let mut cm;
let cm;
match s.cm { Some(ccm) => cm = ccm, _ => return }
match next_comment(s) {
Some(ref cmnt) => {

View File

@ -0,0 +1,42 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Exercise the unused_mut attribute in some positive and negative cases
#[allow(dead_assignment)];
#[allow(unused_variable)];
#[deny(unused_mut)];
fn main() {
// negative cases
let mut a = 3; //~ ERROR: variable does not need to be mutable
let mut a = 2, b = 3; //~ ERROR: variable does not need to be mutable
//~^ ERROR: variable does not need to be mutable
let mut a = ~[3]; //~ ERROR: variable does not need to be mutable
// positive cases
let mut a = 2;
a = 3;
let mut a = ~[];
a.push(3);
let mut a = ~[];
do callback {
a.push(3);
}
}
fn callback(f: &fn()) {}
// make sure the lint attribute can be turned off
#[allow(unused_mut)]
fn foo(mut a: int) {
let mut a = 3;
let mut b = ~[2];
}