diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index daee8de96513..77dea3ae1003 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -218,11 +218,29 @@ pub(crate) struct UnusedVarAssignedOnly { pub(crate) struct UnusedAssign { pub name: Symbol, #[subdiagnostic] + pub overwrite: Option, + #[subdiagnostic] pub suggestion: Option, #[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(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", diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index 90b6f07df836..c3fa88dff377 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -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( diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr index f697662d3ee9..58cdc2510e87 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr @@ -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 diff --git a/tests/ui/destructuring-assignment/warn-unused-duplication.stderr b/tests/ui/destructuring-assignment/warn-unused-duplication.stderr index e16625136aca..59824139c8b3 100644 --- a/tests/ui/destructuring-assignment/warn-unused-duplication.stderr +++ b/tests/ui/destructuring-assignment/warn-unused-duplication.stderr @@ -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 | diff --git a/tests/ui/lint/unused/overwritten-before-read-note-issue-154434.rs b/tests/ui/lint/unused/overwritten-before-read-note-issue-154434.rs new file mode 100644 index 000000000000..c690e79c658a --- /dev/null +++ b/tests/ui/lint/unused/overwritten-before-read-note-issue-154434.rs @@ -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!"); +} diff --git a/tests/ui/lint/unused/overwritten-before-read-note-issue-154434.stderr b/tests/ui/lint/unused/overwritten-before-read-note-issue-154434.stderr new file mode 100644 index 000000000000..237ab562703a --- /dev/null +++ b/tests/ui/lint/unused/overwritten-before-read-note-issue-154434.stderr @@ -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 + diff --git a/tests/ui/lint/unused/unused-assign-148960.stderr b/tests/ui/lint/unused/unused-assign-148960.stderr index 0e23fabd5f56..aa5326cea647 100644 --- a/tests/ui/lint/unused/unused-assign-148960.stderr +++ b/tests/ui/lint/unused/unused-assign-148960.stderr @@ -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 diff --git a/tests/ui/liveness/liveness-consts.stderr b/tests/ui/liveness/liveness-consts.stderr index 2d2750fbaddf..6b4acf1c8de9 100644 --- a/tests/ui/liveness/liveness-consts.stderr +++ b/tests/ui/liveness/liveness-consts.stderr @@ -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 diff --git a/tests/ui/liveness/liveness-dead.stderr b/tests/ui/liveness/liveness-dead.stderr index 4f7dda49cd03..ade0e04d2e7a 100644 --- a/tests/ui/liveness/liveness-dead.stderr +++ b/tests/ui/liveness/liveness-dead.stderr @@ -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 | diff --git a/tests/ui/liveness/liveness-unused.stderr b/tests/ui/liveness/liveness-unused.stderr index f56ca7823e16..9f84c1c998a7 100644 --- a/tests/ui/liveness/liveness-unused.stderr +++ b/tests/ui/liveness/liveness-unused.stderr @@ -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 diff --git a/tests/ui/liveness/liveness-upvars.stderr b/tests/ui/liveness/liveness-upvars.stderr index 0bb5786ab3e2..9f5a3de7365a 100644 --- a/tests/ui/liveness/liveness-upvars.stderr +++ b/tests/ui/liveness/liveness-upvars.stderr @@ -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 diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/general.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/general.stderr index a953e8584494..c888ec292912 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/general.stderr +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/general.stderr @@ -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