diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 8cdf6c983312..cfaa355aa4c8 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -208,6 +208,9 @@ GRS_OBJS = \
rust/rust-const-checker.o \
rust/rust-lint-marklive.o \
rust/rust-lint-unused-var.o \
+ rust/rust-unused-var-checker.o \
+ rust/rust-unused-var-collector.o \
+ rust/rust-unused-var-context.o \
rust/rust-readonly-check.o \
rust/rust-readonly-check2.o \
rust/rust-hir-type-check-path.o \
@@ -441,6 +444,7 @@ RUST_INCLUDES = -I $(srcdir)/rust \
-I $(srcdir)/rust/typecheck \
-I $(srcdir)/rust/checks/lints \
-I $(srcdir)/rust/checks/errors \
+ -I $(srcdir)/rust/checks/lints/unused-var \
-I $(srcdir)/rust/checks/errors/privacy \
-I $(srcdir)/rust/checks/errors/borrowck \
-I $(srcdir)/rust/util \
@@ -510,6 +514,11 @@ rust/%.o: rust/checks/lints/%.cc
$(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
$(POSTCOMPILE)
+# build unused variable checking pass files in rust folder
+rust/%.o: rust/checks/lints/unused-var/%.cc
+ $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
+ $(POSTCOMPILE)
+
# build rust/checks/errors files in rust folder
rust/%.o: rust/checks/errors/%.cc
$(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
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
new file mode 100644
index 000000000000..c6cfd5bb2da6
--- /dev/null
+++ b/gcc/rust/checks/lints/unused-var/rust-unused-var-checker.cc
@@ -0,0 +1,82 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// .
+
+#include "rust-unused-var-checker.h"
+#include "rust-hir-item.h"
+
+#include "options.h"
+
+namespace Rust {
+namespace Analysis {
+UnusedVarChecker::UnusedVarChecker ()
+ : nr_context (
+ Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()),
+ mappings (Analysis::Mappings::get ()),
+ unused_var_context (std::make_unique ())
+{}
+void
+UnusedVarChecker::go (HIR::Crate &crate)
+{
+ UnusedVarCollector collector (*unused_var_context);
+ collector.go (crate);
+ for (auto &item : crate.get_items ())
+ item->accept_vis (*this);
+}
+void
+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'",
+ item.get_identifier ().as_string ().c_str ());
+}
+
+void
+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'",
+ item.get_identifier ().as_string ().c_str ());
+}
+
+void
+UnusedVarChecker::visit (HIR::TraitItemFunc &item)
+{
+ // TODO: check trait item functions if they are not derived.
+}
+void
+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"
+ && !starts_with_under_score)
+ rust_warning_at (pattern.get_locus (), OPT_Wunused_variable,
+ "unused name '%s'",
+ pattern.get_identifier ().as_string ().c_str ());
+}
+} // namespace Analysis
+} // namespace Rust
\ No newline at end of file
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
new file mode 100644
index 000000000000..d916caa2d0ad
--- /dev/null
+++ b/gcc/rust/checks/lints/unused-var/rust-unused-var-checker.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// .
+
+#include "rust-hir-item.h"
+#include "rust-hir-pattern.h"
+#include "rust-hir-visitor.h"
+#include "rust-immutable-name-resolution-context.h"
+#include "rust-unused-var-collector.h"
+
+namespace Rust {
+namespace Analysis {
+class UnusedVarChecker : public HIR::DefaultHIRVisitor
+{
+public:
+ UnusedVarChecker ();
+ void go (HIR::Crate &crate);
+
+private:
+ const Resolver2_0::NameResolutionContext &nr_context;
+ Analysis::Mappings &mappings;
+ std::unique_ptr 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;
+};
+} // namespace Analysis
+} // namespace Rust
\ No newline at end of file
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
new file mode 100644
index 000000000000..deeabdef5503
--- /dev/null
+++ b/gcc/rust/checks/lints/unused-var/rust-unused-var-collector.cc
@@ -0,0 +1,79 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// .
+
+#include "rust-unused-var-collector.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"
+
+namespace Rust {
+namespace Analysis {
+UnusedVarCollector::UnusedVarCollector (UnusedVarContext &context)
+ : nr_context (
+ Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()),
+ mappings (Analysis::Mappings::get ()), unused_var_context (context)
+{}
+void
+UnusedVarCollector::go (HIR::Crate &crate)
+{
+ for (auto &item : crate.get_items ())
+ item->accept_vis (*this);
+}
+
+void
+UnusedVarCollector::visit (HIR::ConstantItem &item)
+{
+ unused_var_context.add_variable (item.get_mappings ().get_hirid ());
+ walk (item);
+}
+
+void
+UnusedVarCollector::visit (HIR::StaticItem &item)
+{
+ unused_var_context.add_variable (item.get_mappings ().get_hirid ());
+ walk (item);
+}
+
+void
+UnusedVarCollector::visit (HIR::IdentifierPattern &pattern)
+{
+ auto id = pattern.get_mappings ().get_hirid ();
+ unused_var_context.add_variable (id);
+}
+
+void
+UnusedVarCollector::visit (HIR::PathInExpression &expr)
+{
+ mark_path_used (expr);
+}
+
+void
+UnusedVarCollector::visit (HIR::QualifiedPathInExpression &expr)
+{
+ mark_path_used (expr);
+}
+
+void
+UnusedVarCollector::visit (HIR::StructExprFieldIdentifier &ident)
+{
+ mark_path_used (ident);
+}
+} // 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
new file mode 100644
index 000000000000..ed338405692f
--- /dev/null
+++ b/gcc/rust/checks/lints/unused-var/rust-unused-var-collector.h
@@ -0,0 +1,59 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// .
+
+#include "rust-hir-expr.h"
+#include "rust-hir-item.h"
+#include "rust-hir-path.h"
+#include "rust-hir-pattern.h"
+#include "rust-hir-visitor.h"
+#include "rust-mapping-common.h"
+#include "rust-name-resolution-context.h"
+#include "rust-unused-var-context.h"
+#include "rust-name-resolver.h"
+
+namespace Rust {
+namespace Analysis {
+class UnusedVarCollector : public HIR::DefaultHIRVisitor
+{
+public:
+ UnusedVarCollector (UnusedVarContext &context);
+ void go (HIR::Crate &crate);
+
+private:
+ const Resolver2_0::NameResolutionContext &nr_context;
+ Analysis::Mappings &mappings;
+ UnusedVarContext &unused_var_context;
+
+ using HIR::DefaultHIRVisitor::visit;
+ virtual void visit (HIR::PathInExpression &expr) override;
+ virtual void visit (HIR::StructExprFieldIdentifier &ident) override;
+ virtual void visit (HIR::ConstantItem &item) override;
+ virtual void visit (HIR::StaticItem &item) override;
+ virtual void visit (HIR::IdentifierPattern &pattern) override;
+ virtual void visit (HIR::QualifiedPathInExpression &expr) override;
+
+ template void mark_path_used (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);
+ }
+};
+} // namespace Analysis
+} // namespace Rust
\ No newline at end of file
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
new file mode 100644
index 000000000000..728d61d217d2
--- /dev/null
+++ b/gcc/rust/checks/lints/unused-var/rust-unused-var-context.cc
@@ -0,0 +1,58 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// .
+
+#include "rust-unused-var-context.h"
+
+namespace Rust {
+namespace Analysis {
+
+void
+UnusedVarContext::add_variable (HirId id)
+{
+ if (is_used.find (id) == is_used.end ())
+ is_used.insert ({id, false});
+}
+
+void
+UnusedVarContext::mark_used (HirId id)
+{
+ is_used[id] = true;
+}
+
+bool
+UnusedVarContext::is_variable_used (HirId id) const
+{
+ auto it = is_used.find (id);
+ return it != is_used.end () && it->second;
+}
+
+std::string
+UnusedVarContext::as_string () const
+{
+ std::stringstream ss;
+ ss << "UnusedVarContext: ";
+ for (const auto &pair : is_used)
+ {
+ ss << "HirId: " << pair.first << " Used: " << (pair.second ? "Yes" : "No")
+ << "\n";
+ }
+ return ss.str ();
+}
+
+} // namespace Analysis
+} // namespace Rust
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
new file mode 100644
index 000000000000..62392c63e6f8
--- /dev/null
+++ b/gcc/rust/checks/lints/unused-var/rust-unused-var-context.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// .
+
+#include "rust-mapping-common.h"
+
+namespace Rust {
+namespace Analysis {
+class UnusedVarContext
+{
+public:
+ void add_variable (HirId id);
+ void mark_used (HirId id);
+
+ bool is_variable_used (HirId id) const;
+
+ std::string as_string () const;
+
+private:
+ std::map is_used;
+};
+} // namespace Analysis
+} // namespace Rust
diff --git a/gcc/rust/lang.opt b/gcc/rust/lang.opt
index d9824f1a5ac2..67a2ae075c95 100644
--- a/gcc/rust/lang.opt
+++ b/gcc/rust/lang.opt
@@ -233,4 +233,8 @@ frust-assume-builtin-offset-of
Rust Var(flag_assume_builtin_offset_of)
Define a built-in offset_of macro in the compiler and assume it is present
+frust-unused-check-2.0
+Rust Var(flag_unused_check_2_0)
+Use the new unused variable check instead of old one
+
; This comment is to ensure we retain the blank line above.
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index c88f46757535..b6bd14627328 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -39,6 +39,7 @@
#include "rust-cfg-parser.h"
#include "rust-lint-scan-deadcode.h"
#include "rust-lint-unused-var.h"
+#include "rust-unused-var-checker.h"
#include "rust-readonly-check.h"
#include "rust-hir-dump.h"
#include "rust-ast-dump.h"
@@ -736,7 +737,12 @@ Session::compile_crate (const char *filename)
{
// lints
Analysis::ScanDeadcode::Scan (hir);
- Analysis::UnusedVariables::Lint (*ctx);
+
+ if (flag_unused_check_2_0)
+ Analysis::UnusedVarChecker ().go (hir);
+ else
+ Analysis::UnusedVariables::Lint (*ctx);
+
Analysis::ReadonlyCheck::Lint (*ctx);
// metadata
diff --git a/gcc/testsuite/rust/compile/static_item_0.rs b/gcc/testsuite/rust/compile/static_item_0.rs
new file mode 100644
index 000000000000..69d8ec40927d
--- /dev/null
+++ b/gcc/testsuite/rust/compile/static_item_0.rs
@@ -0,0 +1,3 @@
+// { dg-additional-options "-frust-unused-check-2.0" }
+static TEST: usize = 1;
+// { dg-warning "unused name" "" { target *-*-* } .-1 }
\ No newline at end of file
diff --git a/gcc/testsuite/rust/compile/template_function_0.rs b/gcc/testsuite/rust/compile/template_function_0.rs
new file mode 100644
index 000000000000..92e3f21cd054
--- /dev/null
+++ b/gcc/testsuite/rust/compile/template_function_0.rs
@@ -0,0 +1,7 @@
+// { dg-additional-options "-frust-unused-check-2.0" }
+#[lang = "sized"]
+pub trait Sized {}
+
+pub fn test (a: usize) -> () {
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+}
\ No newline at end of file