Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions gcc/rust/Make-lang.in
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ GRS_OBJS = \
rust/rust-const-checker.o \
rust/rust-lint-marklive.o \
rust/rust-lint-unused-var.o \
rust/rust-unused-checker.o \
rust/rust-unused-collector.o \
rust/rust-unused-context.o \
rust/rust-readonly-check.o \
rust/rust-hir-type-check-path.o \
rust/rust-unsafe-checker.o \
Expand Down Expand Up @@ -432,6 +435,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 \
-I $(srcdir)/rust/checks/errors/privacy \
-I $(srcdir)/rust/checks/errors/borrowck \
-I $(srcdir)/rust/checks/errors/feature \
Expand Down Expand Up @@ -502,6 +506,11 @@ rust/%.o: rust/checks/lints/%.cc
$(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
$(POSTCOMPILE)

# build unused checking pass files in rust folder
rust/%.o: rust/checks/lints/unused/%.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) $<
Expand Down
99 changes: 99 additions & 0 deletions gcc/rust/checks/lints/unused/rust-unused-checker.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// 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
// <http://www.gnu.org/licenses/>.

#include "rust-unused-checker.h"
#include "rust-hir-expr.h"
#include "rust-hir-item.h"

#include "options.h"

namespace Rust {
namespace Analysis {
UnusedChecker::UnusedChecker ()
: nr_context (
Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()),
mappings (Analysis::Mappings::get ()), unused_context (UnusedContext ())
{}
void
UnusedChecker::go (HIR::Crate &crate)
{
UnusedCollector collector (unused_context);
collector.go (crate);
for (auto &item : crate.get_items ())
item->accept_vis (*this);
}
void
UnusedChecker::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_context.is_variable_used (id) && !starts_with_under_score)
rust_warning_at (item.get_locus (), OPT_Wunused_variable,
"unused variable %qs",
item.get_identifier ().as_string ().c_str ());
}

void
UnusedChecker::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_context.is_variable_used (id) && !starts_with_under_score)
rust_warning_at (item.get_locus (), OPT_Wunused_variable,
"unused variable %qs",
item.get_identifier ().as_string ().c_str ());
}

void
UnusedChecker::visit (HIR::TraitItemFunc &item)
{
// TODO: check trait item functions if they are not derived.
}
void
UnusedChecker::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_context.is_variable_used (id) && var_name != "self"
&& !starts_with_under_score)
rust_warning_at (pattern.get_locus (), OPT_Wunused_variable,
"unused variable %qs",
pattern.get_identifier ().as_string ().c_str ());
}
void

UnusedChecker::visit (HIR::AssignmentExpr &expr)

{
const auto &lhs = expr.get_lhs ();
auto s = lhs.as_string ();
std::string var_name = s.substr (0, s.find (':'));
bool starts_with_under_score = var_name.compare (0, 1, "_") == 0;
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_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
47 changes: 47 additions & 0 deletions gcc/rust/checks/lints/unused/rust-unused-checker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// 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
// <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"
#include "rust-unused-collector.h"
#include "rust-immutable-name-resolution-context.h"

namespace Rust {
namespace Analysis {
class UnusedChecker : public HIR::DefaultHIRVisitor
{
public:
UnusedChecker ();
void go (HIR::Crate &crate);

private:
const Resolver2_0::NameResolutionContext &nr_context;
Analysis::Mappings &mappings;
UnusedContext unused_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
72 changes: 72 additions & 0 deletions gcc/rust/checks/lints/unused/rust-unused-collector.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// 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
// <http://www.gnu.org/licenses/>.

#include "rust-unused-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"

namespace Rust {
namespace Analysis {
UnusedCollector::UnusedCollector (UnusedContext &context)
: nr_context (
Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()),
mappings (Analysis::Mappings::get ()), unused_context (context)
{}
void
UnusedCollector::go (HIR::Crate &crate)
{
for (auto &item : crate.get_items ())
item->accept_vis (*this);
}

void
UnusedCollector::visit (HIR::PathInExpression &expr)
{
mark_path_used (expr);
walk (expr);
}

void
UnusedCollector::visit (HIR::QualifiedPathInExpression &expr)
{
mark_path_used (expr);
walk (expr);
}

void
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.add_assign (def_id, id);
visit_outer_attrs (expr);
expr.get_rhs ().accept_vis (*this);
}

} // namespace Analysis
} // namespace Rust
62 changes: 62 additions & 0 deletions gcc/rust/checks/lints/unused/rust-unused-collector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// 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
// <http://www.gnu.org/licenses/>.

#include "rust-hir-expr.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-context.h"

namespace Rust {
namespace Analysis {
class UnusedCollector : public HIR::DefaultHIRVisitor
{
public:
UnusedCollector (UnusedContext &context);
void go (HIR::Crate &crate);

private:
const Resolver2_0::NameResolutionContext &nr_context;
Analysis::Mappings &mappings;
UnusedContext &unused_context;

using HIR::DefaultHIRVisitor::visit;
virtual void visit (HIR::PathInExpression &expr) override;
virtual void visit (HIR::StructExprFieldIdentifier &ident) override;
virtual void visit (HIR::QualifiedPathInExpression &expr) override;
virtual void visit (HIR::AssignmentExpr &expr) override;

template <typename T> HirId get_def_id (T &path_expr)
{
NodeId ast_node_id = path_expr.get_mappings ().get_nodeid ();
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_context.add_variable (def_id);
unused_context.remove_assign (def_id);
}
};
} // namespace Analysis
} // namespace Rust
70 changes: 70 additions & 0 deletions gcc/rust/checks/lints/unused/rust-unused-context.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// 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
// <http://www.gnu.org/licenses/>.

#include "rust-unused-context.h"

namespace Rust {
namespace Analysis {

void
UnusedContext::add_variable (HirId id)

{
used_vars.emplace (id);
}

bool
UnusedContext::is_variable_used (HirId id) const
{
return used_vars.find (id) != used_vars.end ();
}

void
UnusedContext::add_assign (HirId id_def, HirId id)
{
assigned_vars[id_def].push_back (id);
}

void
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)
{
auto assigned_vec = assigned_vars[id_def];
return std::find (assigned_vec.begin (), assigned_vec.end (), id)
!= assigned_vec.end ();
}

std::string
UnusedContext::as_string () const
{
std::stringstream ss;
ss << "UnusedContext: ";
for (const auto &v : used_vars)
{
ss << "HirId: " << v << "\n";
}
return ss.str ();
}

} // namespace Analysis
} // namespace Rust
Loading