aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-04-09 20:32:21 +0000
committerGitHub <noreply@github.com>2021-04-09 20:32:21 +0000
commit9c97c8588321a106512affb2935b8ec1f836804f (patch)
treecb6779373f416112b0e771d4edb0fbab1aa12b4b
parent85bd4cef64e1be492d1c62eb05d77a6cea1a8d21 (diff)
parentacb0062081056340722e01447d1e266d357e6a17 (diff)
downloadgcc-9c97c8588321a106512affb2935b8ec1f836804f.zip
gcc-9c97c8588321a106512affb2935b8ec1f836804f.tar.gz
gcc-9c97c8588321a106512affb2935b8ec1f836804f.tar.bz2
Merge #357
357: Create liveness analysis for dead code detection r=philberty a=thomasyonug This is the very beginning work for dead code detection. #330 1. create a new test for this feature. 2. handle an extremely simple case. After compiling the rust1, and feed "testsuite/rust.test/xfail_compile/unused.rs" to it. ``` rust fn bar() { // {dg-warning "function is never used: `bar`"} foo(); } fn foo() { // {dg-warning "function is never used: `foo`"} bar(); } fn f() { } fn main() { f(); } ``` we will get some warnings. ``` bash ../gccrs/gcc/testsuite/rust.test/xfail_compile/unused.rs:2:1: warning: function is never used: `[bar]` 2 | fn bar() { // {dg-warning "function is never used: `bar`"} | ^ ../gccrs/gcc/testsuite/rust.test/xfail_compile/unused.rs:6:1: warning: function is never used: `[foo]` 6 | fn foo() { // {dg-warning "function is never used: `foo`"} | ^ ``` Co-authored-by: Thomas Young <wenzhang5800@gmail.com>
-rw-r--r--gcc/rust/Make-lang.in9
-rw-r--r--gcc/rust/analysis/rust-hir-liveness-base.h225
-rw-r--r--gcc/rust/analysis/rust-hir-liveness.cc141
-rw-r--r--gcc/rust/analysis/rust-hir-liveness.h59
-rw-r--r--gcc/rust/analysis/rust-hir-scan-deadcode.h68
-rw-r--r--gcc/rust/rust-session-manager.cc14
-rw-r--r--gcc/testsuite/rust.test/compile/unused.rs16
7 files changed, 531 insertions, 1 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 6e5407b..428e852 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -79,6 +79,7 @@ GRS_OBJS = \
rust/rust-hir-type-check.o \
rust/rust-tyty.o \
rust/rust-tyctx.o \
+ rust/rust-hir-liveness.o \
$(END)
# removed object files from here
@@ -233,7 +234,8 @@ RUST_INCLUDES = -I $(srcdir)/rust \
-I $(srcdir)/rust/hir \
-I $(srcdir)/rust/resolve \
-I $(srcdir)/rust/util \
- -I $(srcdir)/rust/typecheck
+ -I $(srcdir)/rust/typecheck \
+ -I $(srcdir)/rust/analysis
# add files that require cross-folder includes - currently rust-lang.o, rust-lex.o
CFLAGS-rust/rust-lang.o += $(RUST_INCLUDES)
@@ -294,3 +296,8 @@ rust/%.o: rust/typecheck/%.cc
$(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
$(POSTCOMPILE)
+# build rust/analysis files in rust folder
+rust/%.o: rust/analysis/%.cc
+ $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
+ $(POSTCOMPILE)
+
diff --git a/gcc/rust/analysis/rust-hir-liveness-base.h b/gcc/rust/analysis/rust-hir-liveness-base.h
new file mode 100644
index 0000000..483b9c9
--- /dev/null
+++ b/gcc/rust/analysis/rust-hir-liveness-base.h
@@ -0,0 +1,225 @@
+// Copyright (C) 2021 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/>.
+
+#ifndef RUST_HIR_LIVENESS_BASE
+#define RUST_HIR_LIVENESS_BASE
+
+#include "rust-diagnostics.h"
+#include "rust-hir-liveness.h"
+#include "rust-hir-liveness-base.h"
+#include "rust-hir-visitor.h"
+#include "rust-hir-map.h"
+
+namespace Rust {
+namespace Analysis {
+
+class LivenessBase : public HIR::HIRVisitor
+{
+public:
+ virtual ~LivenessBase () {}
+ virtual void visit (HIR::Token &) override {}
+ virtual void visit (HIR::DelimTokenTree &) override {}
+ virtual void visit (HIR::AttrInputMetaItemContainer &) override {}
+ virtual void visit (HIR::IdentifierExpr &) override {}
+ virtual void visit (HIR::Lifetime &) override {}
+ virtual void visit (HIR::LifetimeParam &) override {}
+ virtual void visit (HIR::PathInExpression &) override {}
+ virtual void visit (HIR::TypePathSegment &) override {}
+ virtual void visit (HIR::TypePathSegmentGeneric &) override {}
+ virtual void visit (HIR::TypePathSegmentFunction &) override {}
+ virtual void visit (HIR::TypePath &) override {}
+ virtual void visit (HIR::QualifiedPathInExpression &) override {}
+ virtual void visit (HIR::QualifiedPathInType &) override {}
+
+ virtual void visit (HIR::LiteralExpr &) override {}
+ virtual void visit (HIR::AttrInputLiteral &) override {}
+ virtual void visit (HIR::MetaItemLitExpr &) override {}
+ virtual void visit (HIR::MetaItemPathLit &) override {}
+ virtual void visit (HIR::BorrowExpr &) override {}
+ virtual void visit (HIR::DereferenceExpr &) override {}
+ virtual void visit (HIR::ErrorPropagationExpr &) override {}
+ virtual void visit (HIR::NegationExpr &) override {}
+ virtual void visit (HIR::ArithmeticOrLogicalExpr &) override {}
+ virtual void visit (HIR::ComparisonExpr &) override {}
+ virtual void visit (HIR::LazyBooleanExpr &) override {}
+ virtual void visit (HIR::TypeCastExpr &) override {}
+ virtual void visit (HIR::AssignmentExpr &) override {}
+
+ virtual void visit (HIR::GroupedExpr &) override {}
+
+ virtual void visit (HIR::ArrayElemsValues &) override {}
+ virtual void visit (HIR::ArrayElemsCopied &) override {}
+ virtual void visit (HIR::ArrayExpr &) override {}
+ virtual void visit (HIR::ArrayIndexExpr &) override {}
+ virtual void visit (HIR::TupleExpr &) override {}
+ virtual void visit (HIR::TupleIndexExpr &) override {}
+ virtual void visit (HIR::StructExprStruct &) override {}
+
+ virtual void visit (HIR::StructExprFieldIdentifier &) override {}
+ virtual void visit (HIR::StructExprFieldIdentifierValue &) override {}
+
+ virtual void visit (HIR::StructExprFieldIndexValue &) override {}
+ virtual void visit (HIR::StructExprStructFields &) override {}
+ virtual void visit (HIR::StructExprStructBase &) override {}
+ virtual void visit (HIR::StructExprTuple &) override {}
+ virtual void visit (HIR::StructExprUnit &) override {}
+
+ virtual void visit (HIR::EnumExprFieldIdentifier &) override {}
+ virtual void visit (HIR::EnumExprFieldIdentifierValue &) override {}
+
+ virtual void visit (HIR::EnumExprFieldIndexValue &) override {}
+ virtual void visit (HIR::EnumExprStruct &) override {}
+ virtual void visit (HIR::EnumExprTuple &) override {}
+ virtual void visit (HIR::EnumExprFieldless &) override {}
+ virtual void visit (HIR::CallExpr &) override {}
+ virtual void visit (HIR::MethodCallExpr &) override {}
+ virtual void visit (HIR::FieldAccessExpr &) override {}
+ virtual void visit (HIR::ClosureExprInner &) override {}
+ virtual void visit (HIR::BlockExpr &) override {}
+ virtual void visit (HIR::ClosureExprInnerTyped &) override {}
+ virtual void visit (HIR::ContinueExpr &) override {}
+ virtual void visit (HIR::BreakExpr &) override {}
+ virtual void visit (HIR::RangeFromToExpr &) override {}
+ virtual void visit (HIR::RangeFromExpr &) override {}
+ virtual void visit (HIR::RangeToExpr &) override {}
+ virtual void visit (HIR::RangeFullExpr &) override {}
+ virtual void visit (HIR::RangeFromToInclExpr &) override {}
+ virtual void visit (HIR::RangeToInclExpr &) override {}
+ virtual void visit (HIR::ReturnExpr &) override {}
+ virtual void visit (HIR::UnsafeBlockExpr &) override {}
+ virtual void visit (HIR::LoopExpr &) override {}
+ virtual void visit (HIR::WhileLoopExpr &) override {}
+ virtual void visit (HIR::WhileLetLoopExpr &) override {}
+ virtual void visit (HIR::ForLoopExpr &) override {}
+ virtual void visit (HIR::IfExpr &) override {}
+ virtual void visit (HIR::IfExprConseqElse &) override {}
+ virtual void visit (HIR::IfExprConseqIf &) override {}
+ virtual void visit (HIR::IfExprConseqIfLet &) override {}
+ virtual void visit (HIR::IfLetExpr &) override {}
+ virtual void visit (HIR::IfLetExprConseqElse &) override {}
+ virtual void visit (HIR::IfLetExprConseqIf &) override {}
+ virtual void visit (HIR::IfLetExprConseqIfLet &) override {}
+
+ virtual void visit (HIR::MatchExpr &) override {}
+ virtual void visit (HIR::AwaitExpr &) override {}
+ virtual void visit (HIR::AsyncBlockExpr &) override {}
+
+ virtual void visit (HIR::TypeParam &) override {}
+
+ virtual void visit (HIR::LifetimeWhereClauseItem &) override {}
+ virtual void visit (HIR::TypeBoundWhereClauseItem &) override {}
+ virtual void visit (HIR::Method &) override {}
+ virtual void visit (HIR::ModuleBodied &) override {}
+ virtual void visit (HIR::ModuleNoBody &) override {}
+ virtual void visit (HIR::ExternCrate &) override {}
+
+ virtual void visit (HIR::UseTreeGlob &) override {}
+ virtual void visit (HIR::UseTreeList &) override {}
+ virtual void visit (HIR::UseTreeRebind &) override {}
+ virtual void visit (HIR::UseDeclaration &) override {}
+ virtual void visit (HIR::Function &) override {}
+ virtual void visit (HIR::TypeAlias &) override {}
+ virtual void visit (HIR::StructStruct &) override {}
+ virtual void visit (HIR::TupleStruct &) override {}
+ virtual void visit (HIR::EnumItem &) override {}
+ virtual void visit (HIR::EnumItemTuple &) override {}
+ virtual void visit (HIR::EnumItemStruct &) override {}
+ virtual void visit (HIR::EnumItemDiscriminant &) override {}
+ virtual void visit (HIR::Enum &) override {}
+ virtual void visit (HIR::Union &) override {}
+ virtual void visit (HIR::ConstantItem &) override {}
+ virtual void visit (HIR::StaticItem &) override {}
+ virtual void visit (HIR::TraitItemFunc &) override {}
+ virtual void visit (HIR::TraitItemMethod &) override {}
+ virtual void visit (HIR::TraitItemConst &) override {}
+ virtual void visit (HIR::TraitItemType &) override {}
+ virtual void visit (HIR::Trait &) override {}
+ virtual void visit (HIR::InherentImpl &) override {}
+ virtual void visit (HIR::TraitImpl &) override {}
+
+ virtual void visit (HIR::ExternalStaticItem &) override {}
+ virtual void visit (HIR::ExternalFunctionItem &) override {}
+ virtual void visit (HIR::ExternBlock &) override {}
+
+ virtual void visit (HIR::MacroMatchFragment &) override {}
+ virtual void visit (HIR::MacroMatchRepetition &) override {}
+ virtual void visit (HIR::MacroMatcher &) override {}
+ virtual void visit (HIR::MacroRulesDefinition &) override {}
+ virtual void visit (HIR::MacroInvocation &) override {}
+ virtual void visit (HIR::MetaItemPath &) override {}
+ virtual void visit (HIR::MetaItemSeq &) override {}
+ virtual void visit (HIR::MetaWord &) override {}
+ virtual void visit (HIR::MetaNameValueStr &) override {}
+ virtual void visit (HIR::MetaListPaths &) override {}
+ virtual void visit (HIR::MetaListNameValueStr &) override {}
+
+ virtual void visit (HIR::LiteralPattern &) override {}
+ virtual void visit (HIR::IdentifierPattern &) override {}
+ virtual void visit (HIR::WildcardPattern &) override {}
+
+ virtual void visit (HIR::RangePatternBoundLiteral &) override {}
+ virtual void visit (HIR::RangePatternBoundPath &) override {}
+ virtual void visit (HIR::RangePatternBoundQualPath &) override {}
+ virtual void visit (HIR::RangePattern &) override {}
+ virtual void visit (HIR::ReferencePattern &) override {}
+
+ virtual void visit (HIR::StructPatternFieldTuplePat &) override {}
+ virtual void visit (HIR::StructPatternFieldIdentPat &) override {}
+ virtual void visit (HIR::StructPatternFieldIdent &) override {}
+ virtual void visit (HIR::StructPattern &) override {}
+
+ virtual void visit (HIR::TupleStructItemsNoRange &) override {}
+ virtual void visit (HIR::TupleStructItemsRange &) override {}
+ virtual void visit (HIR::TupleStructPattern &) override {}
+
+ virtual void visit (HIR::TuplePatternItemsMultiple &) override {}
+ virtual void visit (HIR::TuplePatternItemsRanged &) override {}
+ virtual void visit (HIR::TuplePattern &) override {}
+ virtual void visit (HIR::GroupedPattern &) override {}
+ virtual void visit (HIR::SlicePattern &) override {}
+
+ virtual void visit (HIR::EmptyStmt &) override {}
+ virtual void visit (HIR::LetStmt &) override {}
+ virtual void visit (HIR::ExprStmtWithoutBlock &) override {}
+ virtual void visit (HIR::ExprStmtWithBlock &) override {}
+
+ virtual void visit (HIR::TraitBound &) override {}
+ virtual void visit (HIR::ImplTraitType &) override {}
+ virtual void visit (HIR::TraitObjectType &) override {}
+ virtual void visit (HIR::ParenthesisedType &) override {}
+ virtual void visit (HIR::ImplTraitTypeOneBound &) override {}
+ virtual void visit (HIR::TraitObjectTypeOneBound &) override {}
+ virtual void visit (HIR::TupleType &) override {}
+ virtual void visit (HIR::NeverType &) override {}
+ virtual void visit (HIR::RawPointerType &) override {}
+ virtual void visit (HIR::ReferenceType &) override {}
+ virtual void visit (HIR::ArrayType &) override {}
+ virtual void visit (HIR::SliceType &) override {}
+ virtual void visit (HIR::InferredType &) override {}
+ virtual void visit (HIR::BareFunctionType &) override {}
+
+protected:
+ LivenessBase () : mappings (Analysis::Mappings::get ()) {}
+
+ Analysis::Mappings *mappings;
+};
+
+} // namespace Analysis
+} // namespace Rust
+
+#endif
diff --git a/gcc/rust/analysis/rust-hir-liveness.cc b/gcc/rust/analysis/rust-hir-liveness.cc
new file mode 100644
index 0000000..d99d8e3
--- /dev/null
+++ b/gcc/rust/analysis/rust-hir-liveness.cc
@@ -0,0 +1,141 @@
+// Copyright (C) 2021 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-liveness.h"
+#include "rust-hir-full.h"
+#include "rust-name-resolver.h"
+
+namespace Rust {
+namespace Analysis {
+
+class FindEntryPoint : public LivenessBase
+{
+ using Rust::Analysis::LivenessBase::visit;
+
+public:
+ static std::vector<HirId> find (HIR::Crate &crate)
+ {
+ FindEntryPoint findEntryPoint;
+ for (auto it = crate.items.begin (); it != crate.items.end (); it++)
+ {
+ it->get ()->accept_vis (findEntryPoint);
+ }
+ return findEntryPoint.getEntryPoint ();
+ }
+
+ // TODO not only fn main can be a entry point.
+ void visit (HIR::Function &function) override
+ {
+ if (function.get_function_name () == "main")
+ {
+ entryPoints.push_back (function.get_mappings ().get_hirid ());
+ }
+ }
+
+private:
+ FindEntryPoint () : LivenessBase () {}
+ std::vector<HirId> entryPoints;
+ std::vector<HirId> getEntryPoint () { return entryPoints; }
+};
+
+std::set<HirId>
+Liveness::Analysis (HIR::Crate &crate)
+{
+ Liveness liveness (FindEntryPoint::find (crate));
+ liveness.go (crate);
+
+ return liveness.liveSymbols;
+}
+
+void
+Liveness::go (HIR::Crate &crate)
+{
+ while (!worklist.empty ())
+ {
+ HirId hirId = worklist.back ();
+ worklist.pop_back ();
+ scannedSymbols.emplace (hirId);
+ HIR::Item *item
+ = mappings->lookup_hir_item (crate.get_mappings ().get_crate_num (),
+ hirId);
+ if (item == nullptr)
+ continue;
+ liveSymbols.emplace (hirId);
+ item->accept_vis (*this);
+ }
+}
+
+void
+Liveness::visit (HIR::ExprStmtWithoutBlock &stmt)
+{
+ stmt.get_expr ()->accept_vis (*this);
+}
+
+void
+Liveness::visit (HIR::CallExpr &expr)
+{
+ expr.get_fnexpr ()->accept_vis (*this);
+}
+
+void
+Liveness::visit (HIR::PathInExpression &expr)
+{
+ NodeId ast_node_id = expr.get_mappings ().get_nodeid ();
+ NodeId ref_node_id = UNKNOWN_NODEID;
+ if (resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
+ {
+ Resolver::Definition def;
+ if (!resolver->lookup_definition (ref_node_id, &def))
+ {
+ rust_error_at (expr.get_locus (),
+ "unknown reference for resolved name");
+ return;
+ }
+ ref_node_id = def.parent;
+ HirId ref;
+ if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (),
+ ref_node_id, &ref))
+ {
+ rust_error_at (expr.get_locus (), "reverse lookup failure");
+ return;
+ }
+ if (scannedSymbols.find (ref) != scannedSymbols.end ())
+ {
+ worklist.push_back (ref);
+ }
+ liveSymbols.emplace (ref);
+ }
+}
+
+void
+Liveness::visit (HIR::Function &function)
+{
+ function.get_definition ().get ()->accept_vis (*this);
+}
+
+void
+Liveness::visit (HIR::BlockExpr &expr)
+{
+ expr.iterate_stmts ([&] (HIR::Stmt *s) mutable -> bool {
+ s->accept_vis (*this);
+ return true;
+ });
+}
+
+} // namespace Analysis
+} // namespace Rust
diff --git a/gcc/rust/analysis/rust-hir-liveness.h b/gcc/rust/analysis/rust-hir-liveness.h
new file mode 100644
index 0000000..ae80859
--- /dev/null
+++ b/gcc/rust/analysis/rust-hir-liveness.h
@@ -0,0 +1,59 @@
+// Copyright (C) 2021 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/>.
+
+#ifndef RUST_HIR_LIVENESS
+#define RUST_HIR_LIVENESS
+
+#include "rust-hir-full-decls.h"
+#include "rust-hir-map.h"
+#include "rust-hir-liveness-base.h"
+#include "rust-name-resolver.h"
+#include <set>
+
+namespace Rust {
+namespace Analysis {
+
+class Liveness : public LivenessBase
+{
+ using Rust::Analysis::LivenessBase::visit;
+
+public:
+ static std::set<HirId> Analysis (HIR::Crate &crate);
+ void go (HIR::Crate &crate);
+
+ void visit (HIR::ExprStmtWithoutBlock &stmt) override;
+ void visit (HIR::CallExpr &expr) override;
+ void visit (HIR::Function &function) override;
+ void visit (HIR::BlockExpr &expr) override;
+ void visit (HIR::PathInExpression &expr) override;
+
+private:
+ std::vector<HirId> worklist;
+ std::set<HirId> liveSymbols;
+ std::set<HirId> scannedSymbols;
+ Analysis::Mappings *mappings;
+ Resolver::Resolver *resolver;
+ Liveness (std::vector<HirId> worklist)
+ : worklist (worklist), mappings (Analysis::Mappings::get ()),
+ resolver (Resolver::Resolver::get ()){};
+};
+
+} // namespace Analysis
+} // namespace Rust
+
+#endif \ No newline at end of file
diff --git a/gcc/rust/analysis/rust-hir-scan-deadcode.h b/gcc/rust/analysis/rust-hir-scan-deadcode.h
new file mode 100644
index 0000000..3f488e8
--- /dev/null
+++ b/gcc/rust/analysis/rust-hir-scan-deadcode.h
@@ -0,0 +1,68 @@
+// Copyright (C) 2021 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/>.
+
+#ifndef RUST_HIR_SCAN_DEADCODE
+#define RUST_HIR_SCAN_DEADCODE
+
+#include "rust-hir-full-decls.h"
+#include "rust-hir-map.h"
+#include "rust-hir-liveness-base.h"
+#include "rust-name-resolver.h"
+#include "rust-diagnostics.h"
+#include <set>
+
+namespace Rust {
+namespace Analysis {
+
+class ScanDeadcode : public LivenessBase
+{
+ using Rust::Analysis::LivenessBase::visit;
+
+public:
+ static void Scan (HIR::Crate &crate, std::set<HirId> live_symbols)
+ {
+ ScanDeadcode sdc (live_symbols);
+ for (auto it = crate.items.begin (); it != crate.items.end (); it++)
+ {
+ it->get ()->accept_vis (sdc);
+ }
+ };
+
+ void visit (HIR::Function &function) override
+ {
+ HirId hirId = function.get_mappings ().get_hirid ();
+ if (live_symbols.find (hirId) == live_symbols.end ())
+ {
+ rust_warning_at (function.get_locus (), 0,
+ "function is never used: `[%s]`",
+ function.get_function_name ().c_str ());
+ return;
+ }
+ }
+
+private:
+ std::set<HirId> live_symbols;
+ // std::set<HirId> dead_codes;
+
+ ScanDeadcode (std::set<HirId> &live_symbols) : live_symbols (live_symbols){};
+};
+
+} // namespace Analysis
+} // namespace Rust
+
+#endif \ No newline at end of file
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index 885fa60..74e6852 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -48,6 +48,8 @@
#include "rust-ast-resolve.h"
#include "rust-ast-lower.h"
#include "rust-hir-type-check.h"
+#include "rust-hir-liveness.h"
+#include "rust-hir-scan-deadcode.h"
#include "rust-tycheck-dump.h"
#include "rust-ast-resolve-unused.h"
#include "rust-compile.h"
@@ -558,6 +560,18 @@ Session::parse_file (const char *filename)
dump_type_resolution (hir);
}
+ // liveness analysis
+ std::set<HirId> live_symbols = Analysis::Liveness::Analysis (hir);
+
+ if (saw_errors ())
+ return;
+
+ // scan dead code
+ Analysis::ScanDeadcode::Scan (hir, live_symbols);
+
+ if (saw_errors ())
+ return;
+
// scan unused has to be done after type resolution since methods are resolved
// at that point
Resolver::ScanUnused::Scan ();
diff --git a/gcc/testsuite/rust.test/compile/unused.rs b/gcc/testsuite/rust.test/compile/unused.rs
new file mode 100644
index 0000000..1197033
--- /dev/null
+++ b/gcc/testsuite/rust.test/compile/unused.rs
@@ -0,0 +1,16 @@
+
+fn bar() { // {dg-warning "function is never used: `bar`"}
+ foo();
+}
+
+fn foo() { // {dg-warning "function is never used: `foo`"}
+ bar();
+}
+
+fn f() {
+
+}
+
+fn main() {
+ f();
+} \ No newline at end of file