]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: add unused mut lint
authorLucas Ly Ba <lucas.ly-ba@outlook.com>
Mon, 17 Nov 2025 16:13:33 +0000 (16:13 +0000)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 23 Dec 2025 11:16:49 +0000 (12:16 +0100)
gcc/rust/ChangeLog:

* checks/lints/unused/rust-unused-checker.cc (UnusedChecker::UnusedChecker):
Add warning for identifier pattern and field ident pattern in struct
(UnusedChecker::visit): Add methods.
* checks/lints/unused/rust-unused-checker.h: Same here.
* checks/lints/unused/rust-unused-collector.cc (UnusedCollector::UnusedCollector):
Collect unused mut variables
(UnusedCollector::visit): Add methods.
* checks/lints/unused/rust-unused-collector.h: Same here.
* checks/lints/unused/rust-unused-context.cc (UnusedContext::remove_assign):
Add methods for unused mut set.
(UnusedContext::add_mut): Same here.
(UnusedContext::remove_mut): Same here.
(UnusedContext::is_mut_used): Same here.
* checks/lints/unused/rust-unused-context.h: Same here.

gcc/testsuite/ChangeLog:

* rust/compile/unused-mut-identifier_0.rs: New test.
* rust/compile/unused-mut-struct-field_0.rs: New test.

Signed-off-by: Lucas Ly Ba <lucas.ly-ba@outlook.com>
gcc/rust/checks/lints/unused/rust-unused-checker.cc
gcc/rust/checks/lints/unused/rust-unused-checker.h
gcc/rust/checks/lints/unused/rust-unused-collector.cc
gcc/rust/checks/lints/unused/rust-unused-collector.h
gcc/rust/checks/lints/unused/rust-unused-context.cc
gcc/rust/checks/lints/unused/rust-unused-context.h
gcc/testsuite/rust/compile/unused-mut-identifier_0.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/unused-mut-struct-field_0.rs [new file with mode: 0644]

index 9f8394ef90e861c37e6617a1b0ad6a028ea60e84..3ec69e22b46a2f545d3199628d4415fb7994c71b 100644 (file)
@@ -76,6 +76,12 @@ UnusedChecker::visit (HIR::IdentifierPattern &pattern)
     rust_warning_at (pattern.get_locus (), OPT_Wunused_variable,
                     "unused variable %qs",
                     pattern.get_identifier ().as_string ().c_str ());
+
+  if (pattern.is_mut () && !unused_context.is_mut_used (id)
+      && var_name != Values::Keywords::SELF && var_name[0] != '_')
+    rust_warning_at (pattern.get_locus (), OPT_Wunused_variable,
+                    "unused mut %qs",
+                    pattern.get_identifier ().as_string ().c_str ());
 }
 void
 
@@ -92,5 +98,24 @@ UnusedChecker::visit (HIR::AssignmentExpr &expr)
     rust_warning_at (lhs.get_locus (), OPT_Wunused_variable,
                     "unused assignment %qs", var_name.c_str ());
 }
+
+void
+UnusedChecker::visit (HIR::StructPatternFieldIdent &pattern)
+{
+  std::string var_name = pattern.get_identifier ().as_string ();
+  auto id = pattern.get_mappings ().get_hirid ();
+  if (!unused_context.is_variable_used (id)
+      && var_name != Values::Keywords::SELF && var_name[0] != '_')
+    rust_warning_at (pattern.get_locus (), OPT_Wunused_variable,
+                    "unused variable %qs",
+                    pattern.get_identifier ().as_string ().c_str ());
+
+  if (pattern.is_mut () && !unused_context.is_mut_used (id)
+      && var_name != Values::Keywords::SELF && var_name[0] != '_')
+    rust_warning_at (pattern.get_locus (), OPT_Wunused_variable,
+                    "unused mut %qs",
+                    pattern.get_identifier ().as_string ().c_str ());
+}
+
 } // namespace Analysis
 } // namespace Rust
index 6f5f8badefebdaa598bf9110cf55534d789e650d..690435ce455ec940d25b61b084fdd96cbafb64dd 100644 (file)
@@ -42,6 +42,7 @@ private:
   virtual void visit (HIR::StaticItem &item) override;
   virtual void visit (HIR::IdentifierPattern &identifier) override;
   virtual void visit (HIR::AssignmentExpr &identifier) override;
+  virtual void visit (HIR::StructPatternFieldIdent &identifier) override;
 };
 } // namespace Analysis
 } // namespace Rust
index 530c6b0ce9c480de41d333c9c498f567304363b8..b07b09e4a362c96d53a4b7b89662ebd66717572c 100644 (file)
@@ -58,15 +58,35 @@ UnusedCollector::visit (HIR::StructExprFieldIdentifier &ident)
   mark_path_used (ident);
   walk (ident);
 }
+
 void
 UnusedCollector::visit (HIR::AssignmentExpr &expr)
 {
   auto def_id = get_def_id (expr.get_lhs ());
   HirId id = expr.get_lhs ().get_mappings ().get_hirid ();
+  unused_context.remove_mut (def_id);
   unused_context.add_assign (def_id, id);
   visit_outer_attrs (expr);
   expr.get_rhs ().accept_vis (*this);
 }
 
+void
+UnusedCollector::visit (HIR::IdentifierPattern &pattern)
+{
+  if (pattern.is_mut ())
+    unused_context.add_mut (pattern.get_mappings ().get_hirid ());
+
+  walk (pattern);
+}
+
+void
+UnusedCollector::visit (HIR::StructPatternFieldIdent &pattern)
+{
+  if (pattern.is_mut ())
+    unused_context.add_mut (pattern.get_mappings ().get_hirid ());
+
+  walk (pattern);
+}
+
 } // namespace Analysis
 } // namespace Rust
index 7f3ad88fdca6fd221dfcfa9f682f511dff7fed92..ad10677cf879d504d623a30145137d80aeef71a7 100644 (file)
@@ -38,11 +38,19 @@ private:
   UnusedContext &unused_context;
 
   using HIR::DefaultHIRVisitor::visit;
+
+  // Unused var
   virtual void visit (HIR::PathInExpression &expr) override;
   virtual void visit (HIR::StructExprFieldIdentifier &ident) override;
   virtual void visit (HIR::QualifiedPathInExpression &expr) override;
+
+  // Unused assignments
   virtual void visit (HIR::AssignmentExpr &expr) override;
 
+  // Unused mut
+  virtual void visit (HIR::IdentifierPattern &pattern) override;
+  virtual void visit (HIR::StructPatternFieldIdent &pattern) override;
+
   template <typename T> HirId get_def_id (T &path_expr)
   {
     NodeId ast_node_id = path_expr.get_mappings ().get_nodeid ();
index d975865ed588607eb803f62602aecc3e6a2e63b2..29142f4838ed8cff7937f6bfc85757b2cba96cfa 100644 (file)
@@ -46,6 +46,7 @@ UnusedContext::remove_assign (HirId id_def)
   if (assigned_vars.find (id_def) != assigned_vars.end ())
     assigned_vars[id_def].pop_back ();
 }
+
 bool
 UnusedContext::is_variable_assigned (HirId id_def, HirId id)
 {
@@ -54,6 +55,24 @@ UnusedContext::is_variable_assigned (HirId id_def, HirId id)
         != assigned_vec.end ();
 }
 
+void
+UnusedContext::add_mut (HirId id)
+{
+  mutable_vars.emplace (id);
+}
+
+void
+UnusedContext::remove_mut (HirId id)
+{
+  mutable_vars.erase (id);
+}
+
+bool
+UnusedContext::is_mut_used (HirId id) const
+{
+  return mutable_vars.find (id) == mutable_vars.end ();
+}
+
 std::string
 UnusedContext::as_string () const
 {
index 0a9faf53c8c3368d20e84fd747f73375fd1e0231..832779d7dbf82d458a46b4a238f114cd3d334c89 100644 (file)
@@ -24,16 +24,24 @@ namespace Analysis {
 class UnusedContext
 {
 public:
+  // Unused var
   void add_variable (HirId id);
   bool is_variable_used (HirId id) const;
+
+  // Assigned var
   void add_assign (HirId id_def, HirId id);
   void remove_assign (HirId id_def);
   bool is_variable_assigned (HirId id_def, HirId id);
 
+  // Mutable var
+  void add_mut (HirId id);
+  void remove_mut (HirId id);
+  bool is_mut_used (HirId id) const;
   std::string as_string () const;
 
 private:
   std::unordered_set<HirId> used_vars;
+  std::unordered_set<HirId> mutable_vars;
   std::map<HirId, std::vector<HirId>> assigned_vars;
 };
 
diff --git a/gcc/testsuite/rust/compile/unused-mut-identifier_0.rs b/gcc/testsuite/rust/compile/unused-mut-identifier_0.rs
new file mode 100644 (file)
index 0000000..58d1b09
--- /dev/null
@@ -0,0 +1,6 @@
+// { dg-additional-options "-frust-unused-check-2.0" }
+pub fn a() ->i32 {
+    let mut x = 2;
+// { dg-warning "unused mut .x." "" { target *-*-* } .-1 }
+    return x
+}
diff --git a/gcc/testsuite/rust/compile/unused-mut-struct-field_0.rs b/gcc/testsuite/rust/compile/unused-mut-struct-field_0.rs
new file mode 100644 (file)
index 0000000..1662dd3
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-additional-options "-frust-unused-check-2.0" }
+struct Point { x: i32, y: i32 }
+// { dg-warning "field is never read: .x." "" { target *-*-* } .-1 }
+// { dg-warning "field is never read: .y." "" { target *-*-* } .-2 }
+
+pub fn main() -> (i32, i32){
+    let p = Point { x: 1, y: 2 };
+
+    match p {
+        Point { mut x, mut y } => {
+// { dg-warning "unused mut .x." "" { target *-*-* } .-1 }
+// { dg-warning "unused mut .y." "" { target *-*-* } .-2 }
+            return (x,y)
+        }
+    }
+}
+