https://gcc.gnu.org/g:d8d32ffe61e8ac255872bfa5179bdc6d09323fe0
commit r16-6843-gd8d32ffe61e8ac255872bfa5179bdc6d09323fe0 Author: Lucas Ly Ba <[email protected]> Date: Wed Jan 7 11:46:50 2026 +0000 gccrs: add unused label lint gcc/rust/ChangeLog: * checks/lints/unused/rust-unused-checker.cc (UnusedChecker::visit_loop_label): Add warning for unused label in LoopLabel expr. * checks/lints/unused/rust-unused-checker.h: Likewise. * checks/lints/unused/rust-unused-collector.cc (UnusedCollector::visit): Check in BreakExpr and ContinueExpr if a label is used. * checks/lints/unused/rust-unused-collector.h: Likewise. * checks/lints/unused/rust-unused-context.cc (UnusedContext::add_label): Method helper. (UnusedContext::is_label_used): Likewise * checks/lints/unused/rust-unused-context.h: Likewise. gcc/testsuite/ChangeLog: * rust/compile/unused-label_0.rs: New test. Signed-off-by: Lucas Ly Ba <[email protected]> Diff: --- .../checks/lints/unused/rust-unused-checker.cc | 11 +++++++++ gcc/rust/checks/lints/unused/rust-unused-checker.h | 1 + .../checks/lints/unused/rust-unused-collector.cc | 18 ++++++++++++++ .../checks/lints/unused/rust-unused-collector.h | 10 ++++++++ .../checks/lints/unused/rust-unused-context.cc | 13 ++++++++++ gcc/rust/checks/lints/unused/rust-unused-context.h | 6 +++++ gcc/testsuite/rust/compile/unused-label_0.rs | 28 ++++++++++++++++++++++ 7 files changed, 87 insertions(+) diff --git a/gcc/rust/checks/lints/unused/rust-unused-checker.cc b/gcc/rust/checks/lints/unused/rust-unused-checker.cc index 235acd6a4065..751306171deb 100644 --- a/gcc/rust/checks/lints/unused/rust-unused-checker.cc +++ b/gcc/rust/checks/lints/unused/rust-unused-checker.cc @@ -124,5 +124,16 @@ UnusedChecker::visit (HIR::EmptyStmt &stmt) "unnecessary trailing semicolons"); } +void +UnusedChecker::visit_loop_label (HIR::LoopLabel &label) +{ + auto lifetime = label.get_lifetime (); + std::string var_name = lifetime.to_string (); + auto id = lifetime.get_mappings ().get_hirid (); + if (!unused_context.is_label_used (id) && var_name[0] != '_') + rust_warning_at (lifetime.get_locus (), OPT_Wunused_variable, + "unused label %qs", lifetime.to_string ().c_str ()); +} + } // namespace Analysis } // namespace Rust diff --git a/gcc/rust/checks/lints/unused/rust-unused-checker.h b/gcc/rust/checks/lints/unused/rust-unused-checker.h index 061d0c6f0029..eeb94679ddd2 100644 --- a/gcc/rust/checks/lints/unused/rust-unused-checker.h +++ b/gcc/rust/checks/lints/unused/rust-unused-checker.h @@ -44,6 +44,7 @@ private: virtual void visit (HIR::AssignmentExpr &identifier) override; virtual void visit (HIR::StructPatternFieldIdent &identifier) override; virtual void visit (HIR::EmptyStmt &stmt) override; + virtual void visit_loop_label (HIR::LoopLabel &label) override; }; } // namespace Analysis } // namespace Rust diff --git a/gcc/rust/checks/lints/unused/rust-unused-collector.cc b/gcc/rust/checks/lints/unused/rust-unused-collector.cc index b00fa84ff162..6767678c6f36 100644 --- a/gcc/rust/checks/lints/unused/rust-unused-collector.cc +++ b/gcc/rust/checks/lints/unused/rust-unused-collector.cc @@ -88,5 +88,23 @@ UnusedCollector::visit (HIR::StructPatternFieldIdent &pattern) walk (pattern); } +void +UnusedCollector::visit (HIR::BreakExpr &expr) +{ + if (!expr.has_label ()) + return; + mark_label_used (expr.get_label ()); + walk (expr); +} + +void +UnusedCollector::visit (HIR::ContinueExpr &expr) +{ + if (!expr.has_label ()) + return; + mark_label_used (expr.get_label ()); + walk (expr); +} + } // namespace Analysis } // namespace Rust diff --git a/gcc/rust/checks/lints/unused/rust-unused-collector.h b/gcc/rust/checks/lints/unused/rust-unused-collector.h index 6bcdcb868bc2..1944089d16c5 100644 --- a/gcc/rust/checks/lints/unused/rust-unused-collector.h +++ b/gcc/rust/checks/lints/unused/rust-unused-collector.h @@ -51,6 +51,10 @@ private: virtual void visit (HIR::IdentifierPattern &pattern) override; virtual void visit (HIR::StructPatternFieldIdent &pattern) override; + // Unused label + virtual void visit (HIR::BreakExpr &expr) override; + virtual void visit (HIR::ContinueExpr &expr) override; + template <typename T> HirId get_def_id (T &path_expr) { NodeId ast_node_id = path_expr.get_mappings ().get_nodeid (); @@ -65,6 +69,12 @@ private: unused_context.add_variable (def_id); unused_context.remove_assign (def_id); } + + template <typename T> void mark_label_used (T &path_expr) + { + auto def_id = get_def_id (path_expr); + unused_context.add_label (def_id); + } }; } // namespace Analysis } // namespace Rust diff --git a/gcc/rust/checks/lints/unused/rust-unused-context.cc b/gcc/rust/checks/lints/unused/rust-unused-context.cc index 40862edc3fc9..9b26e01bccee 100644 --- a/gcc/rust/checks/lints/unused/rust-unused-context.cc +++ b/gcc/rust/checks/lints/unused/rust-unused-context.cc @@ -73,6 +73,19 @@ UnusedContext::is_mut_used (HirId id) const return mutable_vars.find (id) == mutable_vars.end (); } +void +UnusedContext::add_label (HirId id) + +{ + used_labels.emplace (id); +} + +bool +UnusedContext::is_label_used (HirId id) const +{ + return used_labels.find (id) != used_labels.end (); +} + std::string UnusedContext::as_string () const { diff --git a/gcc/rust/checks/lints/unused/rust-unused-context.h b/gcc/rust/checks/lints/unused/rust-unused-context.h index 9ab67ff35e88..1405ebb64965 100644 --- a/gcc/rust/checks/lints/unused/rust-unused-context.h +++ b/gcc/rust/checks/lints/unused/rust-unused-context.h @@ -37,12 +37,18 @@ public: void add_mut (HirId id); void remove_mut (HirId id); bool is_mut_used (HirId id) const; + + // Unused label + void add_label (HirId id); + bool is_label_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; + std::unordered_set<HirId> used_labels; }; } // namespace Analysis diff --git a/gcc/testsuite/rust/compile/unused-label_0.rs b/gcc/testsuite/rust/compile/unused-label_0.rs new file mode 100644 index 000000000000..3c868976de51 --- /dev/null +++ b/gcc/testsuite/rust/compile/unused-label_0.rs @@ -0,0 +1,28 @@ +// { dg-additional-options "-frust-unused-check-2.0" } + +pub fn foo_1() { + 'a: loop { + break 'a; + } +} + +pub fn foo_2() { + 'a: loop { +// { dg-warning "unused label ..a." "" { target *-*-* } .-1 } + break; + } +} + + +pub fn bar_1() { + 'a: loop { + continue 'a; + } +} + +pub fn bar_2() { + 'a: loop { +// { dg-warning "unused label ..a." "" { target *-*-* } .-1 } + continue; + } +}
