From d3c69a4c0dd98af2611b7553d1a65afef6a6ccb0 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Thu, 28 Jan 2021 23:56:13 +0900 Subject: [PATCH] Warn write-only fields --- compiler/rustc_passes/src/dead.rs | 19 ++++++++++++++ .../borrowck/borrowck-assign-to-subfield.rs | 1 + .../ui/lint/dead-code/write-only-field.rs | 20 ++++++++++++++ .../ui/lint/dead-code/write-only-field.stderr | 26 +++++++++++++++++++ 4 files changed, 66 insertions(+) create mode 100644 src/test/ui/lint/dead-code/write-only-field.rs create mode 100644 src/test/ui/lint/dead-code/write-only-field.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 3b1b53553d5e4..a4798b9ae1f0c 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -37,6 +37,19 @@ fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { ) } +fn base_expr<'a>(expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { + let mut current = expr; + loop { + match current.kind { + hir::ExprKind::Field(base, ..) => { + current = base; + } + _ => break, + } + } + current +} + struct MarkSymbolVisitor<'tcx> { worklist: Vec, tcx: TyCtxt<'tcx>, @@ -263,6 +276,12 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { hir::ExprKind::MethodCall(..) => { self.lookup_and_handle_method(expr.hir_id); } + hir::ExprKind::Assign(ref left, ref right, ..) => { + // Ignore write to field + self.visit_expr(base_expr(left)); + self.visit_expr(right); + return; + } hir::ExprKind::Field(ref lhs, ..) => { self.handle_field_access(&lhs, expr.hir_id); } diff --git a/src/test/ui/borrowck/borrowck-assign-to-subfield.rs b/src/test/ui/borrowck/borrowck-assign-to-subfield.rs index 050d702b625ab..dfa3a561ec7ee 100644 --- a/src/test/ui/borrowck/borrowck-assign-to-subfield.rs +++ b/src/test/ui/borrowck/borrowck-assign-to-subfield.rs @@ -1,5 +1,6 @@ // run-pass // pretty-expanded FIXME #23616 +#![allow(dead_code)] pub fn main() { struct A { diff --git a/src/test/ui/lint/dead-code/write-only-field.rs b/src/test/ui/lint/dead-code/write-only-field.rs new file mode 100644 index 0000000000000..78cfcfda8f971 --- /dev/null +++ b/src/test/ui/lint/dead-code/write-only-field.rs @@ -0,0 +1,20 @@ +#![deny(dead_code)] + +struct S { + f: i32, //~ ERROR: field is never read + sub: Sub, //~ ERROR: field is never read +} + +struct Sub { + f: i32, //~ ERROR: field is never read +} + +fn field_write(s: &mut S) { + s.f = 1; + s.sub.f = 2; +} + +fn main() { + let mut s = S { f: 0, sub: Sub { f: 0 } }; + field_write(&mut s); +} diff --git a/src/test/ui/lint/dead-code/write-only-field.stderr b/src/test/ui/lint/dead-code/write-only-field.stderr new file mode 100644 index 0000000000000..70d2149665b20 --- /dev/null +++ b/src/test/ui/lint/dead-code/write-only-field.stderr @@ -0,0 +1,26 @@ +error: field is never read: `f` + --> $DIR/write-only-field.rs:4:5 + | +LL | f: i32, + | ^^^^^^ + | +note: the lint level is defined here + --> $DIR/write-only-field.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: field is never read: `sub` + --> $DIR/write-only-field.rs:5:5 + | +LL | sub: Sub, + | ^^^^^^^^ + +error: field is never read: `f` + --> $DIR/write-only-field.rs:9:5 + | +LL | f: i32, + | ^^^^^^ + +error: aborting due to 3 previous errors +