From: Lucas Ly Ba <[email protected]>

gcc/rust/ChangeLog:

        * checks/lints/unused-var/rust-unused-var-checker.cc (UnusedVarChecker):
        Implement unused assignments warning.
        (UnusedVarChecker::go): Remove unique pointer unused var context.
        (UnusedVarChecker::visit): Visit AssignExpr in HIR default visitor.
        * checks/lints/unused-var/rust-unused-var-checker.h: Add visit method.
        * checks/lints/unused-var/rust-unused-var-collector.cc 
(UnusedVarCollector):
        Collect warnings for assignments.
        (UnusedVarCollector::visit): Visit AssignExpr in HIR default visitor.
        * checks/lints/unused-var/rust-unused-var-collector.h: Add visit method.
        * checks/lints/unused-var/rust-unused-var-context.cc 
(UnusedVarContext::add_assign):
        Add assignment in map.
        (UnusedVarContext::remove_assign): Remove assignment in map.
        (UnusedVarContext::is_variable_assigned): Check if a variable is 
assigned.
        * checks/lints/unused-var/rust-unused-var-context.h: Add a map to stock 
assignments.

gcc/testsuite/ChangeLog:

        * rust/compile/issue-4260_0.rs: New test.

Signed-off-by: Lucas Ly Ba <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/e33909eff1e6d22e5ea31c167882605be94f503d

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4285

 .../unused-var/rust-unused-var-checker.cc     | 37 +++++++++++++------
 .../unused-var/rust-unused-var-checker.h      |  6 ++-
 .../unused-var/rust-unused-var-collector.cc   | 15 +++++++-
 .../unused-var/rust-unused-var-collector.h    | 18 ++++++---
 .../unused-var/rust-unused-var-context.cc     | 20 ++++++++++
 .../unused-var/rust-unused-var-context.h      |  6 ++-
 gcc/testsuite/rust/compile/issue-4260_0.rs    | 22 +++++++++++
 7 files changed, 103 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/issue-4260_0.rs

diff --git a/gcc/rust/checks/lints/unused-var/rust-unused-var-checker.cc 
b/gcc/rust/checks/lints/unused-var/rust-unused-var-checker.cc
index c6cfd5bb2..e4df446f7 100644
--- a/gcc/rust/checks/lints/unused-var/rust-unused-var-checker.cc
+++ b/gcc/rust/checks/lints/unused-var/rust-unused-var-checker.cc
@@ -17,6 +17,7 @@
 // <http://www.gnu.org/licenses/>.
 
 #include "rust-unused-var-checker.h"
+#include "rust-hir-expr.h"
 #include "rust-hir-item.h"
 
 #include "options.h"
@@ -27,12 +28,12 @@ UnusedVarChecker::UnusedVarChecker ()
   : nr_context (
     Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()),
     mappings (Analysis::Mappings::get ()),
-    unused_var_context (std::make_unique<UnusedVarContext> ())
+    unused_var_context (UnusedVarContext ())
 {}
 void
 UnusedVarChecker::go (HIR::Crate &crate)
 {
-  UnusedVarCollector collector (*unused_var_context);
+  UnusedVarCollector collector (unused_var_context);
   collector.go (crate);
   for (auto &item : crate.get_items ())
     item->accept_vis (*this);
@@ -43,9 +44,8 @@ UnusedVarChecker::visit (HIR::ConstantItem &item)
   std::string var_name = item.get_identifier ().as_string ();
   bool starts_with_under_score = var_name.compare (0, 1, "_") == 0;
   auto id = item.get_mappings ().get_hirid ();
-  if (!unused_var_context->is_variable_used (id) && !starts_with_under_score)
-    rust_warning_at (item.get_locus (), OPT_Wunused_variable,
-                    "unused name '%s'",
+  if (!unused_var_context.is_variable_used (id) && !starts_with_under_score)
+    rust_warning_at (item.get_locus (), OPT_Wunused_variable, "unused name 
%qs",
                     item.get_identifier ().as_string ().c_str ());
 }
 
@@ -55,9 +55,8 @@ UnusedVarChecker::visit (HIR::StaticItem &item)
   std::string var_name = item.get_identifier ().as_string ();
   bool starts_with_under_score = var_name.compare (0, 1, "_") == 0;
   auto id = item.get_mappings ().get_hirid ();
-  if (!unused_var_context->is_variable_used (id) && !starts_with_under_score)
-    rust_warning_at (item.get_locus (), OPT_Wunused_variable,
-                    "unused name '%s'",
+  if (!unused_var_context.is_variable_used (id) && !starts_with_under_score)
+    rust_warning_at (item.get_locus (), OPT_Wunused_variable, "unused name 
%qs",
                     item.get_identifier ().as_string ().c_str ());
 }
 
@@ -72,11 +71,27 @@ UnusedVarChecker::visit (HIR::IdentifierPattern &pattern)
   std::string var_name = pattern.get_identifier ().as_string ();
   bool starts_with_under_score = var_name.compare (0, 1, "_") == 0;
   auto id = pattern.get_mappings ().get_hirid ();
-  if (!unused_var_context->is_variable_used (id) && var_name != "self"
+  if (!unused_var_context.is_variable_used (id) && var_name != "self"
       && !starts_with_under_score)
     rust_warning_at (pattern.get_locus (), OPT_Wunused_variable,
-                    "unused name '%s'",
+                    "unused name %qs",
                     pattern.get_identifier ().as_string ().c_str ());
 }
+void
+
+UnusedVarChecker::visit (HIR::AssignmentExpr &expr)
+
+{
+  const auto &lhs = expr.get_lhs ();
+  auto var_name = lhs.to_string ();
+  NodeId ast_node_id = lhs.get_mappings ().get_nodeid ();
+  NodeId def_id = nr_context.lookup (ast_node_id).value ();
+  HirId id = mappings.lookup_node_to_hir (def_id).value ();
+  if (unused_var_context.is_variable_assigned (id,
+                                              lhs.get_mappings ().get_hirid ())
+      && !starts_with_under_score)
+    rust_warning_at (lhs.get_locus (), OPT_Wunused_variable,
+                    "unused assignment %qs", var_name.c_str ());
+}
 } // namespace Analysis
-} // namespace Rust
\ No newline at end of file
+} // namespace Rust
diff --git a/gcc/rust/checks/lints/unused-var/rust-unused-var-checker.h 
b/gcc/rust/checks/lints/unused-var/rust-unused-var-checker.h
index d916caa2d..bb9c8ac85 100644
--- a/gcc/rust/checks/lints/unused-var/rust-unused-var-checker.h
+++ b/gcc/rust/checks/lints/unused-var/rust-unused-var-checker.h
@@ -16,6 +16,7 @@
 // along with GCC; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
+#include "rust-hir-expr.h"
 #include "rust-hir-item.h"
 #include "rust-hir-pattern.h"
 #include "rust-hir-visitor.h"
@@ -33,13 +34,14 @@ public:
 private:
   const Resolver2_0::NameResolutionContext &nr_context;
   Analysis::Mappings &mappings;
-  std::unique_ptr<UnusedVarContext> unused_var_context;
+  UnusedVarContext unused_var_context;
 
   using HIR::DefaultHIRVisitor::visit;
   virtual void visit (HIR::TraitItemFunc &decl) override;
   virtual void visit (HIR::ConstantItem &item) override;
   virtual void visit (HIR::StaticItem &item) override;
   virtual void visit (HIR::IdentifierPattern &identifier) override;
+  virtual void visit (HIR::AssignmentExpr &identifier) override;
 };
 } // namespace Analysis
-} // namespace Rust
\ No newline at end of file
+} // namespace Rust
diff --git a/gcc/rust/checks/lints/unused-var/rust-unused-var-collector.cc 
b/gcc/rust/checks/lints/unused-var/rust-unused-var-collector.cc
index deeabdef5..e9e98c5f2 100644
--- a/gcc/rust/checks/lints/unused-var/rust-unused-var-collector.cc
+++ b/gcc/rust/checks/lints/unused-var/rust-unused-var-collector.cc
@@ -17,11 +17,13 @@
 // <http://www.gnu.org/licenses/>.
 
 #include "rust-unused-var-collector.h"
+#include "rust-hir-expr.h"
 #include "rust-hir-full-decls.h"
 #include "rust-hir-item.h"
 #include "rust-hir-path.h"
 #include "rust-hir-pattern.h"
 #include "rust-immutable-name-resolution-context.h"
+#include "tree-check.h"
 
 namespace Rust {
 namespace Analysis {
@@ -54,8 +56,7 @@ UnusedVarCollector::visit (HIR::StaticItem &item)
 void
 UnusedVarCollector::visit (HIR::IdentifierPattern &pattern)
 {
-  auto id = pattern.get_mappings ().get_hirid ();
-  unused_var_context.add_variable (id);
+  unused_var_context.add_variable (pattern.get_mappings ().get_hirid ());
 }
 
 void
@@ -75,5 +76,15 @@ UnusedVarCollector::visit (HIR::StructExprFieldIdentifier 
&ident)
 {
   mark_path_used (ident);
 }
+void
+UnusedVarCollector::visit (HIR::AssignmentExpr &expr)
+{
+  auto def_id = get_def_id (expr.get_lhs ());
+  HirId id = expr.get_lhs ().get_mappings ().get_hirid ();
+  unused_var_context.add_assign (def_id, id);
+  visit_outer_attrs (expr);
+  expr.get_rhs ().accept_vis (*this);
+}
+
 } // namespace Analysis
 } // namespace Rust
diff --git a/gcc/rust/checks/lints/unused-var/rust-unused-var-collector.h 
b/gcc/rust/checks/lints/unused-var/rust-unused-var-collector.h
index ed3384056..e3fed0c29 100644
--- a/gcc/rust/checks/lints/unused-var/rust-unused-var-collector.h
+++ b/gcc/rust/checks/lints/unused-var/rust-unused-var-collector.h
@@ -46,14 +46,22 @@ private:
   virtual void visit (HIR::StaticItem &item) override;
   virtual void visit (HIR::IdentifierPattern &pattern) override;
   virtual void visit (HIR::QualifiedPathInExpression &expr) override;
+  virtual void visit (HIR::AssignmentExpr &expr) override;
 
-  template <typename T> void mark_path_used (T &path_expr)
+  template <typename T> HirId get_def_id (T &path_expr)
   {
     NodeId ast_node_id = path_expr.get_mappings ().get_nodeid ();
-    NodeId def_id = nr_context.lookup (ast_node_id).value ();
-    HirId hir_id = mappings.lookup_node_to_hir (def_id).value ();
-    unused_var_context.mark_used (hir_id);
+    NodeId id = nr_context.lookup (ast_node_id).value ();
+    HirId def_id = mappings.lookup_node_to_hir (id).value ();
+    return def_id;
+  }
+
+  template <typename T> void mark_path_used (T &path_expr)
+  {
+    auto def_id = get_def_id (path_expr);
+    unused_var_context.mark_used (def_id);
+    unused_var_context.remove_assign (def_id);
   }
 };
 } // namespace Analysis
-} // namespace Rust
\ No newline at end of file
+} // namespace Rust
diff --git a/gcc/rust/checks/lints/unused-var/rust-unused-var-context.cc 
b/gcc/rust/checks/lints/unused-var/rust-unused-var-context.cc
index 728d61d21..435fba46a 100644
--- a/gcc/rust/checks/lints/unused-var/rust-unused-var-context.cc
+++ b/gcc/rust/checks/lints/unused-var/rust-unused-var-context.cc
@@ -41,6 +41,26 @@ UnusedVarContext::is_variable_used (HirId id) const
   return it != is_used.end () && it->second;
 }
 
+void
+UnusedVarContext::add_assign (HirId id_def, HirId id)
+{
+  assigned_vars[id_def].push_back (id);
+}
+
+void
+UnusedVarContext::remove_assign (HirId id_def)
+{
+  if (assigned_vars.find (id_def) != assigned_vars.end ())
+    assigned_vars[id_def].pop_back ();
+}
+bool
+UnusedVarContext::is_variable_assigned (HirId id_def, HirId id)
+{
+  auto assigned_vec = assigned_vars[id_def];
+  return std::find (assigned_vec.begin (), assigned_vec.end (), id)
+        != assigned_vec.end ();
+}
+
 std::string
 UnusedVarContext::as_string () const
 {
diff --git a/gcc/rust/checks/lints/unused-var/rust-unused-var-context.h 
b/gcc/rust/checks/lints/unused-var/rust-unused-var-context.h
index 14f89da78..bde793def 100644
--- a/gcc/rust/checks/lints/unused-var/rust-unused-var-context.h
+++ b/gcc/rust/checks/lints/unused-var/rust-unused-var-context.h
@@ -26,13 +26,17 @@ class UnusedVarContext
 public:
   void add_variable (HirId id);
   void mark_used (HirId id);
-
   bool is_variable_used (HirId id) const;
 
+  void add_assign (HirId id_def, HirId id);
+  void remove_assign (HirId id_def);
+  bool is_variable_assigned (HirId id_def, HirId id);
+
   std::string as_string () const;
 
 private:
   std::map<HirId, bool> is_used;
+  std::map<HirId, std::vector<HirId>> assigned_vars;
 };
 
 } // namespace Analysis
diff --git a/gcc/testsuite/rust/compile/issue-4260_0.rs 
b/gcc/testsuite/rust/compile/issue-4260_0.rs
new file mode 100644
index 000000000..b6f1fba3b
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-4260_0.rs
@@ -0,0 +1,22 @@
+// { dg-additional-options "-frust-unused-check-2.0" }
+pub fn a()->i32 {
+    let mut a = 1;
+    a = 2;
+// { dg-warning "unused assignment .a." "" { target *-*-* } .-1 }
+    a = 3;
+// { dg-warning "unused assignment .a." "" { target *-*-* } .-1 }
+    a = 4;
+// { dg-warning "unused assignment .a." "" { target *-*-* } .-1 }
+    a = 5;
+    let mut b = a;
+    b = 1;
+// { dg-warning "unused assignment .b." "" { target *-*-* } .-1 }
+    b = 2;
+// { dg-warning "unused assignment .b." "" { target *-*-* } .-1 }
+    b = 3;
+// { dg-warning "unused assignment .b." "" { target *-*-* } .-1 }
+    b = 4;
+// { dg-warning "unused assignment .b." "" { target *-*-* } .-1 }
+    b = 5;
+    return b
+}

base-commit: 38bccd0ece07aaa52ae906036fb428edec74655d
-- 
2.52.0

Reply via email to