Label overwritten assignments for never read assignments

This commit is contained in:
yukang
2026-03-27 14:29:56 +08:00
parent 37cfa179be
commit 86796ddaa0
12 changed files with 171 additions and 90 deletions
@@ -218,11 +218,29 @@ pub(crate) struct UnusedVarAssignedOnly {
pub(crate) struct UnusedAssign {
pub name: Symbol,
#[subdiagnostic]
pub overwrite: Option<UnusedAssignOverwrite>,
#[subdiagnostic]
pub suggestion: Option<UnusedAssignSuggestion>,
#[help("maybe it is overwritten before being read?")]
pub help: bool,
}
pub(crate) struct UnusedAssignOverwrite {
pub assigned_span: Span,
pub overwrite_span: Span,
pub name: Symbol,
}
impl Subdiagnostic for UnusedAssignOverwrite {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_label(self.assigned_span, "this value is reassigned later and never used");
diag.span_label(
self.overwrite_span,
format!("`{}` is overwritten here before the previous value is read", self.name),
);
}
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(
"you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding",
+33 -10
View File
@@ -1094,29 +1094,49 @@ fn report_unused_assignments(self) {
self.body,
);
// We probed MIR in reverse order for dataflow.
// We revert the vector to give a consistent order to the user.
for (source_info, Access { live, kind, is_direct }) in statements.into_iter().rev() {
// By convention, underscore-prefixed bindings are allowed to be unused explicitly.
if name.as_str().starts_with('_') {
continue;
}
let mut next_direct_assign = None;
let mut dead_statements = Vec::with_capacity(statements.len());
for (source_info, Access { live, kind, is_direct }) in statements.into_iter() {
let overwrite = match (kind, is_direct, next_direct_assign) {
(AccessKind::Assign, true, Some(overwrite_span)) => {
Some(errors::UnusedAssignOverwrite {
assigned_span: source_info.span,
overwrite_span,
name,
})
}
_ => None,
};
if kind == AccessKind::Assign && is_direct {
next_direct_assign = Some(source_info.span);
}
if live {
continue;
}
// If this place was dropped and has non-trivial drop,
// skip reporting field assignments.
if !is_direct && is_maybe_drop_guard {
continue;
}
dead_statements.push((source_info, kind, is_direct, overwrite));
}
// We probed MIR in reverse order for dataflow.
// Emit diagnostics in source order instead.
for (source_info, kind, is_direct, overwrite) in dead_statements.into_iter().rev() {
// Report the dead assignment.
let Some(hir_id) = source_info.scope.lint_root(&self.body.source_scopes) else {
continue;
};
// By convention, underscore-prefixed bindings are allowed to be unused explicitly
if name.as_str().starts_with('_') {
break;
}
match kind {
AccessKind::Assign => {
let suggestion = annotate_mut_binding_to_immutable_binding(
@@ -1126,11 +1146,14 @@ fn report_unused_assignments(self) {
source_info.span,
self.body,
);
let overwrite =
if suggestion.is_none() && is_direct { overwrite } else { None };
let help = suggestion.is_none() && overwrite.is_none();
tcx.emit_node_span_lint(
lint::builtin::UNUSED_ASSIGNMENTS,
hir_id,
source_info.span,
errors::UnusedAssign { name, help: suggestion.is_none(), suggestion },
errors::UnusedAssign { name, overwrite, help, suggestion },
)
}
AccessKind::Param => tcx.emit_node_span_lint(
@@ -80,9 +80,10 @@ warning: value assigned to `e.x` is never read
--> $DIR/liveness.rs:74:13
|
LL | e.x = Some("e1");
| ^^^^^^^^^^^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^^^^^^^^^^^ this value is reassigned later and never used
LL |
LL | e.x = Some("e2");
| ---------------- `e.x` is overwritten here before the previous value is read
warning: value assigned to `e.x` is never read
--> $DIR/liveness.rs:76:13
@@ -104,9 +105,10 @@ warning: value assigned to `b` is never read
--> $DIR/liveness.rs:77:13
|
LL | b = Some("e1");
| ^^^^^^^^^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^^^^^^^^^ this value is reassigned later and never used
LL |
LL | b = Some("e2");
| -------------- `b` is overwritten here before the previous value is read
warning: value assigned to `b` is never read
--> $DIR/liveness.rs:79:13
@@ -120,17 +122,17 @@ warning: value assigned to `d.x` is never read
--> $DIR/liveness.rs:68:13
|
LL | d.x = Some("d1");
| ^^^^^^^^^^^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^^^^^^^^^^^ this value is reassigned later and never used
LL | d.x = Some("d2");
| ---------------- `d.x` is overwritten here before the previous value is read
warning: value assigned to `a` is never read
--> $DIR/liveness.rs:70:13
|
LL | a = Some("d1");
| ^^^^^^^^^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^^^^^^^^^ this value is reassigned later and never used
LL | a = Some("d2");
| -------------- `a` is overwritten here before the previous value is read
warning: 16 warnings emitted
@@ -2,9 +2,10 @@ warning: value assigned to `a` is never read
--> $DIR/warn-unused-duplication.rs:9:6
|
LL | (a, a) = (0, 1);
| ^
| ^ - `a` is overwritten here before the previous value is read
| |
| this value is reassigned later and never used
|
= help: maybe it is overwritten before being read?
note: the lint level is defined here
--> $DIR/warn-unused-duplication.rs:3:9
|
@@ -0,0 +1,9 @@
//@ check-pass
//@ compile-flags: -W unused-assignments
fn main() {
let mut d = String::from("hello"); //~ WARN value assigned to `d` is never read
d = String::from("ahoy");
println!("{d}, world!");
}
@@ -0,0 +1,12 @@
warning: value assigned to `d` is never read
--> $DIR/overwritten-before-read-note-issue-154434.rs:5:17
|
LL | let mut d = String::from("hello");
| ^^^^^^^^^^^^^^^^^^^^^ this value is reassigned later and never used
LL | d = String::from("ahoy");
| - `d` is overwritten here before the previous value is read
|
= note: requested on the command line with `-W unused-assignments`
warning: 1 warning emitted
@@ -2,9 +2,10 @@ error: value assigned to `value` is never read
--> $DIR/unused-assign-148960.rs:6:21
|
LL | let mut value = b"0".to_vec();
| ^^^^^^^^^^^^^
| ^^^^^^^^^^^^^ this value is reassigned later and never used
LL | value = b"1".to_vec();
| ----- `value` is overwritten here before the previous value is read
|
= help: maybe it is overwritten before being read?
note: the lint level is defined here
--> $DIR/unused-assign-148960.rs:2:9
|
@@ -16,25 +17,25 @@ error: value assigned to `x` is never read
--> $DIR/unused-assign-148960.rs:12:17
|
LL | let mut x = 1;
| ^
|
= help: maybe it is overwritten before being read?
| ^ this value is reassigned later and never used
LL | x = 2;
| ----- `x` is overwritten here before the previous value is read
error: value assigned to `x` is never read
--> $DIR/unused-assign-148960.rs:13:5
|
LL | x = 2;
| ^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^ this value is reassigned later and never used
LL | x = 3;
| ----- `x` is overwritten here before the previous value is read
error: value assigned to `p` is never read
--> $DIR/unused-assign-148960.rs:24:17
|
LL | let mut p = Point { x: 1, y: 1 };
| ^^^^^^^^^^^^^^^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^^^^^^^^^^^^^^^ this value is reassigned later and never used
LL | p = Point { x: 2, y: 2 };
| ------------------------ `p` is overwritten here before the previous value is read
error: variable `foo` is assigned to, but never used
--> $DIR/unused-assign-148960.rs:38:9
+6 -6
View File
@@ -44,17 +44,17 @@ warning: value assigned to `b` is never read
--> $DIR/liveness-consts.rs:18:17
|
LL | let mut b = 1;
| ^
|
= help: maybe it is overwritten before being read?
| ^ this value is reassigned later and never used
LL | b += 1;
| ------ `b` is overwritten here before the previous value is read
warning: value assigned to `b` is never read
--> $DIR/liveness-consts.rs:19:5
|
LL | b += 1;
| ^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^ this value is reassigned later and never used
LL | b = 42;
| ------ `b` is overwritten here before the previous value is read
warning: unused variable: `z`
--> $DIR/liveness-consts.rs:62:13
+3 -2
View File
@@ -2,9 +2,10 @@ error: value assigned to `x` is never read
--> $DIR/liveness-dead.rs:9:24
|
LL | let mut x: isize = 3;
| ^
| ^ this value is reassigned later and never used
LL | x = 4;
| ----- `x` is overwritten here before the previous value is read
|
= help: maybe it is overwritten before being read?
note: the lint level is defined here
--> $DIR/liveness-dead.rs:2:9
|
+40 -30
View File
@@ -167,49 +167,55 @@ error: value assigned to `a` is never read
--> $DIR/liveness-unused.rs:183:5
|
LL | a += b;
| ^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^ this value is reassigned later and never used
LL |
LL | a -= c;
| ------ `a` is overwritten here before the previous value is read
error: value assigned to `a` is never read
--> $DIR/liveness-unused.rs:185:5
|
LL | a -= c;
| ^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^ this value is reassigned later and never used
LL |
LL | a *= d;
| ------ `a` is overwritten here before the previous value is read
error: value assigned to `a` is never read
--> $DIR/liveness-unused.rs:187:5
|
LL | a *= d;
| ^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^ this value is reassigned later and never used
LL |
LL | a /= e;
| ------ `a` is overwritten here before the previous value is read
error: value assigned to `a` is never read
--> $DIR/liveness-unused.rs:189:5
|
LL | a /= e;
| ^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^ this value is reassigned later and never used
LL |
LL | a |= f;
| ------ `a` is overwritten here before the previous value is read
error: value assigned to `a` is never read
--> $DIR/liveness-unused.rs:191:5
|
LL | a |= f;
| ^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^ this value is reassigned later and never used
LL |
LL | a &= g;
| ------ `a` is overwritten here before the previous value is read
error: value assigned to `a` is never read
--> $DIR/liveness-unused.rs:193:5
|
LL | a &= g;
| ^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^ this value is reassigned later and never used
LL |
LL | a %= h;
| ------ `a` is overwritten here before the previous value is read
error: value assigned to `a` is never read
--> $DIR/liveness-unused.rs:195:5
@@ -231,33 +237,37 @@ error: value assigned to `a` is never read
--> $DIR/liveness-unused.rs:229:5
|
LL | a += b;
| ^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^ this value is reassigned later and never used
LL |
LL | a -= c;
| ------ `a` is overwritten here before the previous value is read
error: value assigned to `a` is never read
--> $DIR/liveness-unused.rs:231:5
|
LL | a -= c;
| ^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^ this value is reassigned later and never used
LL |
LL | a *= d;
| ------ `a` is overwritten here before the previous value is read
error: value assigned to `a` is never read
--> $DIR/liveness-unused.rs:233:5
|
LL | a *= d;
| ^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^ this value is reassigned later and never used
LL |
LL | a /= e;
| ------ `a` is overwritten here before the previous value is read
error: value assigned to `a` is never read
--> $DIR/liveness-unused.rs:235:5
|
LL | a /= e;
| ^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^ this value is reassigned later and never used
LL |
LL | a %= f;
| ------ `a` is overwritten here before the previous value is read
error: value assigned to `a` is never read
--> $DIR/liveness-unused.rs:237:5
+17 -15
View File
@@ -112,9 +112,10 @@ warning: value assigned to `e` is never read
--> $DIR/liveness-upvars.rs:82:13
|
LL | e = Some("e1");
| ^^^^^^^^^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^^^^^^^^^ this value is reassigned later and never used
LL |
LL | e = Some("e2");
| -------------- `e` is overwritten here before the previous value is read
warning: value assigned to `e` is never read
--> $DIR/liveness-upvars.rs:84:13
@@ -128,9 +129,9 @@ warning: value assigned to `d` is never read
--> $DIR/liveness-upvars.rs:78:13
|
LL | d = Some("d1");
| ^^^^^^^^^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^^^^^^^^^ this value is reassigned later and never used
LL | d = Some("d2");
| -------------- `d` is overwritten here before the previous value is read
warning: value assigned to `v` is never read
--> $DIR/liveness-upvars.rs:92:13
@@ -176,9 +177,10 @@ warning: value assigned to `state` is never read
--> $DIR/liveness-upvars.rs:131:9
|
LL | state = 4;
| ^^^^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^^^^ this value is reassigned later and never used
...
LL | state = 5;
| --------- `state` is overwritten here before the previous value is read
warning: value assigned to `state` is never read
--> $DIR/liveness-upvars.rs:134:9
@@ -192,17 +194,17 @@ warning: value assigned to `s` is never read
--> $DIR/liveness-upvars.rs:143:9
|
LL | s = 1;
| ^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^ this value is reassigned later and never used
LL | yield (s = 2);
| ------- `s` is overwritten here before the previous value is read
warning: value assigned to `s` is never read
--> $DIR/liveness-upvars.rs:145:9
|
LL | s = yield ();
| ^^^^^^^^^^^^
|
= help: maybe it is overwritten before being read?
| ^^^^^^^^^^^^ this value is reassigned later and never used
LL | s = 3;
| ----- `s` is overwritten here before the previous value is read
warning: 25 warnings emitted
@@ -2,9 +2,11 @@ warning: value assigned to `b` is never read
--> $DIR/general.rs:60:25
|
LL | (Some(a), &Some(mut b)) => {
| ^^^^^
| ^^^^^ this value is reassigned later and never used
...
LL | b = 7;
| ----- `b` is overwritten here before the previous value is read
|
= help: maybe it is overwritten before being read?
= note: `#[warn(unused_assignments)]` (part of `#[warn(unused)]`) on by default
warning: 1 warning emitted