Skip to content

Commit 9c97c85

Browse files
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 <[email protected]>
2 parents 85bd4ce + acb0062 commit 9c97c85

File tree

7 files changed

+531
-1
lines changed

7 files changed

+531
-1
lines changed

gcc/rust/Make-lang.in

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ GRS_OBJS = \
7979
rust/rust-hir-type-check.o \
8080
rust/rust-tyty.o \
8181
rust/rust-tyctx.o \
82+
rust/rust-hir-liveness.o \
8283
$(END)
8384
# removed object files from here
8485

@@ -233,7 +234,8 @@ RUST_INCLUDES = -I $(srcdir)/rust \
233234
-I $(srcdir)/rust/hir \
234235
-I $(srcdir)/rust/resolve \
235236
-I $(srcdir)/rust/util \
236-
-I $(srcdir)/rust/typecheck
237+
-I $(srcdir)/rust/typecheck \
238+
-I $(srcdir)/rust/analysis
237239

238240
# add files that require cross-folder includes - currently rust-lang.o, rust-lex.o
239241
CFLAGS-rust/rust-lang.o += $(RUST_INCLUDES)
@@ -294,3 +296,8 @@ rust/%.o: rust/typecheck/%.cc
294296
$(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
295297
$(POSTCOMPILE)
296298

299+
# build rust/analysis files in rust folder
300+
rust/%.o: rust/analysis/%.cc
301+
$(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
302+
$(POSTCOMPILE)
303+
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
// Copyright (C) 2021 Free Software Foundation, Inc.
2+
3+
// This file is part of GCC.
4+
5+
// GCC is free software; you can redistribute it and/or modify it under
6+
// the terms of the GNU General Public License as published by the Free
7+
// Software Foundation; either version 3, or (at your option) any later
8+
// version.
9+
10+
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11+
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
// for more details.
14+
15+
// You should have received a copy of the GNU General Public License
16+
// along with GCC; see the file COPYING3. If not see
17+
// <http://www.gnu.org/licenses/>.
18+
19+
#ifndef RUST_HIR_LIVENESS_BASE
20+
#define RUST_HIR_LIVENESS_BASE
21+
22+
#include "rust-diagnostics.h"
23+
#include "rust-hir-liveness.h"
24+
#include "rust-hir-liveness-base.h"
25+
#include "rust-hir-visitor.h"
26+
#include "rust-hir-map.h"
27+
28+
namespace Rust {
29+
namespace Analysis {
30+
31+
class LivenessBase : public HIR::HIRVisitor
32+
{
33+
public:
34+
virtual ~LivenessBase () {}
35+
virtual void visit (HIR::Token &) override {}
36+
virtual void visit (HIR::DelimTokenTree &) override {}
37+
virtual void visit (HIR::AttrInputMetaItemContainer &) override {}
38+
virtual void visit (HIR::IdentifierExpr &) override {}
39+
virtual void visit (HIR::Lifetime &) override {}
40+
virtual void visit (HIR::LifetimeParam &) override {}
41+
virtual void visit (HIR::PathInExpression &) override {}
42+
virtual void visit (HIR::TypePathSegment &) override {}
43+
virtual void visit (HIR::TypePathSegmentGeneric &) override {}
44+
virtual void visit (HIR::TypePathSegmentFunction &) override {}
45+
virtual void visit (HIR::TypePath &) override {}
46+
virtual void visit (HIR::QualifiedPathInExpression &) override {}
47+
virtual void visit (HIR::QualifiedPathInType &) override {}
48+
49+
virtual void visit (HIR::LiteralExpr &) override {}
50+
virtual void visit (HIR::AttrInputLiteral &) override {}
51+
virtual void visit (HIR::MetaItemLitExpr &) override {}
52+
virtual void visit (HIR::MetaItemPathLit &) override {}
53+
virtual void visit (HIR::BorrowExpr &) override {}
54+
virtual void visit (HIR::DereferenceExpr &) override {}
55+
virtual void visit (HIR::ErrorPropagationExpr &) override {}
56+
virtual void visit (HIR::NegationExpr &) override {}
57+
virtual void visit (HIR::ArithmeticOrLogicalExpr &) override {}
58+
virtual void visit (HIR::ComparisonExpr &) override {}
59+
virtual void visit (HIR::LazyBooleanExpr &) override {}
60+
virtual void visit (HIR::TypeCastExpr &) override {}
61+
virtual void visit (HIR::AssignmentExpr &) override {}
62+
63+
virtual void visit (HIR::GroupedExpr &) override {}
64+
65+
virtual void visit (HIR::ArrayElemsValues &) override {}
66+
virtual void visit (HIR::ArrayElemsCopied &) override {}
67+
virtual void visit (HIR::ArrayExpr &) override {}
68+
virtual void visit (HIR::ArrayIndexExpr &) override {}
69+
virtual void visit (HIR::TupleExpr &) override {}
70+
virtual void visit (HIR::TupleIndexExpr &) override {}
71+
virtual void visit (HIR::StructExprStruct &) override {}
72+
73+
virtual void visit (HIR::StructExprFieldIdentifier &) override {}
74+
virtual void visit (HIR::StructExprFieldIdentifierValue &) override {}
75+
76+
virtual void visit (HIR::StructExprFieldIndexValue &) override {}
77+
virtual void visit (HIR::StructExprStructFields &) override {}
78+
virtual void visit (HIR::StructExprStructBase &) override {}
79+
virtual void visit (HIR::StructExprTuple &) override {}
80+
virtual void visit (HIR::StructExprUnit &) override {}
81+
82+
virtual void visit (HIR::EnumExprFieldIdentifier &) override {}
83+
virtual void visit (HIR::EnumExprFieldIdentifierValue &) override {}
84+
85+
virtual void visit (HIR::EnumExprFieldIndexValue &) override {}
86+
virtual void visit (HIR::EnumExprStruct &) override {}
87+
virtual void visit (HIR::EnumExprTuple &) override {}
88+
virtual void visit (HIR::EnumExprFieldless &) override {}
89+
virtual void visit (HIR::CallExpr &) override {}
90+
virtual void visit (HIR::MethodCallExpr &) override {}
91+
virtual void visit (HIR::FieldAccessExpr &) override {}
92+
virtual void visit (HIR::ClosureExprInner &) override {}
93+
virtual void visit (HIR::BlockExpr &) override {}
94+
virtual void visit (HIR::ClosureExprInnerTyped &) override {}
95+
virtual void visit (HIR::ContinueExpr &) override {}
96+
virtual void visit (HIR::BreakExpr &) override {}
97+
virtual void visit (HIR::RangeFromToExpr &) override {}
98+
virtual void visit (HIR::RangeFromExpr &) override {}
99+
virtual void visit (HIR::RangeToExpr &) override {}
100+
virtual void visit (HIR::RangeFullExpr &) override {}
101+
virtual void visit (HIR::RangeFromToInclExpr &) override {}
102+
virtual void visit (HIR::RangeToInclExpr &) override {}
103+
virtual void visit (HIR::ReturnExpr &) override {}
104+
virtual void visit (HIR::UnsafeBlockExpr &) override {}
105+
virtual void visit (HIR::LoopExpr &) override {}
106+
virtual void visit (HIR::WhileLoopExpr &) override {}
107+
virtual void visit (HIR::WhileLetLoopExpr &) override {}
108+
virtual void visit (HIR::ForLoopExpr &) override {}
109+
virtual void visit (HIR::IfExpr &) override {}
110+
virtual void visit (HIR::IfExprConseqElse &) override {}
111+
virtual void visit (HIR::IfExprConseqIf &) override {}
112+
virtual void visit (HIR::IfExprConseqIfLet &) override {}
113+
virtual void visit (HIR::IfLetExpr &) override {}
114+
virtual void visit (HIR::IfLetExprConseqElse &) override {}
115+
virtual void visit (HIR::IfLetExprConseqIf &) override {}
116+
virtual void visit (HIR::IfLetExprConseqIfLet &) override {}
117+
118+
virtual void visit (HIR::MatchExpr &) override {}
119+
virtual void visit (HIR::AwaitExpr &) override {}
120+
virtual void visit (HIR::AsyncBlockExpr &) override {}
121+
122+
virtual void visit (HIR::TypeParam &) override {}
123+
124+
virtual void visit (HIR::LifetimeWhereClauseItem &) override {}
125+
virtual void visit (HIR::TypeBoundWhereClauseItem &) override {}
126+
virtual void visit (HIR::Method &) override {}
127+
virtual void visit (HIR::ModuleBodied &) override {}
128+
virtual void visit (HIR::ModuleNoBody &) override {}
129+
virtual void visit (HIR::ExternCrate &) override {}
130+
131+
virtual void visit (HIR::UseTreeGlob &) override {}
132+
virtual void visit (HIR::UseTreeList &) override {}
133+
virtual void visit (HIR::UseTreeRebind &) override {}
134+
virtual void visit (HIR::UseDeclaration &) override {}
135+
virtual void visit (HIR::Function &) override {}
136+
virtual void visit (HIR::TypeAlias &) override {}
137+
virtual void visit (HIR::StructStruct &) override {}
138+
virtual void visit (HIR::TupleStruct &) override {}
139+
virtual void visit (HIR::EnumItem &) override {}
140+
virtual void visit (HIR::EnumItemTuple &) override {}
141+
virtual void visit (HIR::EnumItemStruct &) override {}
142+
virtual void visit (HIR::EnumItemDiscriminant &) override {}
143+
virtual void visit (HIR::Enum &) override {}
144+
virtual void visit (HIR::Union &) override {}
145+
virtual void visit (HIR::ConstantItem &) override {}
146+
virtual void visit (HIR::StaticItem &) override {}
147+
virtual void visit (HIR::TraitItemFunc &) override {}
148+
virtual void visit (HIR::TraitItemMethod &) override {}
149+
virtual void visit (HIR::TraitItemConst &) override {}
150+
virtual void visit (HIR::TraitItemType &) override {}
151+
virtual void visit (HIR::Trait &) override {}
152+
virtual void visit (HIR::InherentImpl &) override {}
153+
virtual void visit (HIR::TraitImpl &) override {}
154+
155+
virtual void visit (HIR::ExternalStaticItem &) override {}
156+
virtual void visit (HIR::ExternalFunctionItem &) override {}
157+
virtual void visit (HIR::ExternBlock &) override {}
158+
159+
virtual void visit (HIR::MacroMatchFragment &) override {}
160+
virtual void visit (HIR::MacroMatchRepetition &) override {}
161+
virtual void visit (HIR::MacroMatcher &) override {}
162+
virtual void visit (HIR::MacroRulesDefinition &) override {}
163+
virtual void visit (HIR::MacroInvocation &) override {}
164+
virtual void visit (HIR::MetaItemPath &) override {}
165+
virtual void visit (HIR::MetaItemSeq &) override {}
166+
virtual void visit (HIR::MetaWord &) override {}
167+
virtual void visit (HIR::MetaNameValueStr &) override {}
168+
virtual void visit (HIR::MetaListPaths &) override {}
169+
virtual void visit (HIR::MetaListNameValueStr &) override {}
170+
171+
virtual void visit (HIR::LiteralPattern &) override {}
172+
virtual void visit (HIR::IdentifierPattern &) override {}
173+
virtual void visit (HIR::WildcardPattern &) override {}
174+
175+
virtual void visit (HIR::RangePatternBoundLiteral &) override {}
176+
virtual void visit (HIR::RangePatternBoundPath &) override {}
177+
virtual void visit (HIR::RangePatternBoundQualPath &) override {}
178+
virtual void visit (HIR::RangePattern &) override {}
179+
virtual void visit (HIR::ReferencePattern &) override {}
180+
181+
virtual void visit (HIR::StructPatternFieldTuplePat &) override {}
182+
virtual void visit (HIR::StructPatternFieldIdentPat &) override {}
183+
virtual void visit (HIR::StructPatternFieldIdent &) override {}
184+
virtual void visit (HIR::StructPattern &) override {}
185+
186+
virtual void visit (HIR::TupleStructItemsNoRange &) override {}
187+
virtual void visit (HIR::TupleStructItemsRange &) override {}
188+
virtual void visit (HIR::TupleStructPattern &) override {}
189+
190+
virtual void visit (HIR::TuplePatternItemsMultiple &) override {}
191+
virtual void visit (HIR::TuplePatternItemsRanged &) override {}
192+
virtual void visit (HIR::TuplePattern &) override {}
193+
virtual void visit (HIR::GroupedPattern &) override {}
194+
virtual void visit (HIR::SlicePattern &) override {}
195+
196+
virtual void visit (HIR::EmptyStmt &) override {}
197+
virtual void visit (HIR::LetStmt &) override {}
198+
virtual void visit (HIR::ExprStmtWithoutBlock &) override {}
199+
virtual void visit (HIR::ExprStmtWithBlock &) override {}
200+
201+
virtual void visit (HIR::TraitBound &) override {}
202+
virtual void visit (HIR::ImplTraitType &) override {}
203+
virtual void visit (HIR::TraitObjectType &) override {}
204+
virtual void visit (HIR::ParenthesisedType &) override {}
205+
virtual void visit (HIR::ImplTraitTypeOneBound &) override {}
206+
virtual void visit (HIR::TraitObjectTypeOneBound &) override {}
207+
virtual void visit (HIR::TupleType &) override {}
208+
virtual void visit (HIR::NeverType &) override {}
209+
virtual void visit (HIR::RawPointerType &) override {}
210+
virtual void visit (HIR::ReferenceType &) override {}
211+
virtual void visit (HIR::ArrayType &) override {}
212+
virtual void visit (HIR::SliceType &) override {}
213+
virtual void visit (HIR::InferredType &) override {}
214+
virtual void visit (HIR::BareFunctionType &) override {}
215+
216+
protected:
217+
LivenessBase () : mappings (Analysis::Mappings::get ()) {}
218+
219+
Analysis::Mappings *mappings;
220+
};
221+
222+
} // namespace Analysis
223+
} // namespace Rust
224+
225+
#endif
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// Copyright (C) 2021 Free Software Foundation, Inc.
2+
3+
// This file is part of GCC.
4+
5+
// GCC is free software; you can redistribute it and/or modify it under
6+
// the terms of the GNU General Public License as published by the Free
7+
// Software Foundation; either version 3, or (at your option) any later
8+
// version.
9+
10+
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11+
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
// for more details.
14+
15+
// You should have received a copy of the GNU General Public License
16+
// along with GCC; see the file COPYING3. If not see
17+
// <http://www.gnu.org/licenses/>.
18+
19+
#include "rust-hir-liveness.h"
20+
#include "rust-hir-full.h"
21+
#include "rust-name-resolver.h"
22+
23+
namespace Rust {
24+
namespace Analysis {
25+
26+
class FindEntryPoint : public LivenessBase
27+
{
28+
using Rust::Analysis::LivenessBase::visit;
29+
30+
public:
31+
static std::vector<HirId> find (HIR::Crate &crate)
32+
{
33+
FindEntryPoint findEntryPoint;
34+
for (auto it = crate.items.begin (); it != crate.items.end (); it++)
35+
{
36+
it->get ()->accept_vis (findEntryPoint);
37+
}
38+
return findEntryPoint.getEntryPoint ();
39+
}
40+
41+
// TODO not only fn main can be a entry point.
42+
void visit (HIR::Function &function) override
43+
{
44+
if (function.get_function_name () == "main")
45+
{
46+
entryPoints.push_back (function.get_mappings ().get_hirid ());
47+
}
48+
}
49+
50+
private:
51+
FindEntryPoint () : LivenessBase () {}
52+
std::vector<HirId> entryPoints;
53+
std::vector<HirId> getEntryPoint () { return entryPoints; }
54+
};
55+
56+
std::set<HirId>
57+
Liveness::Analysis (HIR::Crate &crate)
58+
{
59+
Liveness liveness (FindEntryPoint::find (crate));
60+
liveness.go (crate);
61+
62+
return liveness.liveSymbols;
63+
}
64+
65+
void
66+
Liveness::go (HIR::Crate &crate)
67+
{
68+
while (!worklist.empty ())
69+
{
70+
HirId hirId = worklist.back ();
71+
worklist.pop_back ();
72+
scannedSymbols.emplace (hirId);
73+
HIR::Item *item
74+
= mappings->lookup_hir_item (crate.get_mappings ().get_crate_num (),
75+
hirId);
76+
if (item == nullptr)
77+
continue;
78+
liveSymbols.emplace (hirId);
79+
item->accept_vis (*this);
80+
}
81+
}
82+
83+
void
84+
Liveness::visit (HIR::ExprStmtWithoutBlock &stmt)
85+
{
86+
stmt.get_expr ()->accept_vis (*this);
87+
}
88+
89+
void
90+
Liveness::visit (HIR::CallExpr &expr)
91+
{
92+
expr.get_fnexpr ()->accept_vis (*this);
93+
}
94+
95+
void
96+
Liveness::visit (HIR::PathInExpression &expr)
97+
{
98+
NodeId ast_node_id = expr.get_mappings ().get_nodeid ();
99+
NodeId ref_node_id = UNKNOWN_NODEID;
100+
if (resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
101+
{
102+
Resolver::Definition def;
103+
if (!resolver->lookup_definition (ref_node_id, &def))
104+
{
105+
rust_error_at (expr.get_locus (),
106+
"unknown reference for resolved name");
107+
return;
108+
}
109+
ref_node_id = def.parent;
110+
HirId ref;
111+
if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (),
112+
ref_node_id, &ref))
113+
{
114+
rust_error_at (expr.get_locus (), "reverse lookup failure");
115+
return;
116+
}
117+
if (scannedSymbols.find (ref) != scannedSymbols.end ())
118+
{
119+
worklist.push_back (ref);
120+
}
121+
liveSymbols.emplace (ref);
122+
}
123+
}
124+
125+
void
126+
Liveness::visit (HIR::Function &function)
127+
{
128+
function.get_definition ().get ()->accept_vis (*this);
129+
}
130+
131+
void
132+
Liveness::visit (HIR::BlockExpr &expr)
133+
{
134+
expr.iterate_stmts ([&] (HIR::Stmt *s) mutable -> bool {
135+
s->accept_vis (*this);
136+
return true;
137+
});
138+
}
139+
140+
} // namespace Analysis
141+
} // namespace Rust

0 commit comments

Comments
 (0)