Branch data Line data Source code
1 : : // Copyright (C) 2021-2024 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 : : // The idea is that all reachable symbols are live, codes called
20 : : // from live codes are live, and everything else is dead.
21 : :
22 : : #include "rust-lint-marklive.h"
23 : : #include "rust-hir-full.h"
24 : : #include "rust-name-resolver.h"
25 : :
26 : : namespace Rust {
27 : : namespace Analysis {
28 : :
29 : : // This class trys to find the live symbols which can be used as
30 : : // seeds in MarkLive
31 : : //
32 : : // 1. TODO: explicit live
33 : : // - Attribute like #[allow(dead_code)]
34 : : // - Attribute like #[lang=".."], it's not a intra-crate item.
35 : : // 2. TODO: foreign item
36 : 6558 : class FindEntryPoint : public MarkLiveBase
37 : : {
38 : : using Rust::Analysis::MarkLiveBase::visit;
39 : :
40 : : public:
41 : 3279 : static std::vector<HirId> find (HIR::Crate &crate)
42 : : {
43 : 6558 : FindEntryPoint findEntryPoint;
44 : 15733 : for (auto &it : crate.get_items ())
45 : 12454 : it->accept_vis (findEntryPoint);
46 : 3279 : return findEntryPoint.getEntryPoint ();
47 : 3279 : }
48 : :
49 : : // TODO not only fn main can be a entry point.
50 : 4610 : void visit (HIR::Function &function) override
51 : : {
52 : 4610 : if (function.get_function_name ().as_string () == "main")
53 : : {
54 : 3039 : entryPoints.push_back (function.get_mappings ().get_hirid ());
55 : : }
56 : 4610 : }
57 : :
58 : : private:
59 : 3279 : FindEntryPoint () : MarkLiveBase () {}
60 : : std::vector<HirId> entryPoints;
61 : 3279 : std::vector<HirId> getEntryPoint () { return entryPoints; }
62 : : };
63 : :
64 : : std::set<HirId>
65 : 3279 : MarkLive::Analysis (HIR::Crate &crate)
66 : : {
67 : 3279 : MarkLive marklive (FindEntryPoint::find (crate));
68 : 3279 : marklive.go (crate);
69 : :
70 : 3279 : return marklive.liveSymbols;
71 : 3279 : }
72 : :
73 : : // pop a live symbol from worklist every iteration,
74 : : // if it's a function then walk the function body, and
75 : : // 1. save all the live symbols in worklist which is
76 : : // visited first time
77 : : // 2. save all the live symbols in liveSymbols
78 : : void
79 : 3279 : MarkLive::go (HIR::Crate &)
80 : : {
81 : 31291 : while (!worklist.empty ())
82 : : {
83 : 28012 : HirId hirId = worklist.back ();
84 : 28012 : worklist.pop_back ();
85 : 28012 : scannedSymbols.emplace (hirId);
86 : 28012 : HIR::Item *item = mappings->lookup_hir_item (hirId);
87 : 28012 : liveSymbols.emplace (hirId);
88 : 28012 : if (item != nullptr)
89 : : {
90 : 11316 : item->accept_vis (*this);
91 : : }
92 : : else
93 : : { // the item maybe inside a trait impl
94 : 16696 : HirId parent_impl_id = UNKNOWN_HIRID;
95 : 16696 : HIR::ImplItem *implItem
96 : 16696 : = mappings->lookup_hir_implitem (hirId, &parent_impl_id);
97 : 16696 : if (implItem != nullptr)
98 : 762 : implItem->accept_vis (*this);
99 : : }
100 : : }
101 : 3279 : }
102 : :
103 : : void
104 : 31922 : MarkLive::visit (HIR::PathInExpression &expr)
105 : : {
106 : : // We should iterate every path segment in order to mark the struct which
107 : : // is used in expression like Foo::bar(), we should mark the Foo alive.
108 : 31922 : expr.iterate_path_segments ([&] (HIR::PathExprSegment &seg) -> bool {
109 : 33642 : return visit_path_segment (seg);
110 : : });
111 : :
112 : : // after iterate the path segments, we should mark functions and associated
113 : : // functions alive.
114 : 31922 : NodeId ast_node_id = expr.get_mappings ().get_nodeid ();
115 : 31922 : NodeId ref_node_id = UNKNOWN_NODEID;
116 : 31922 : find_ref_node_id (ast_node_id, ref_node_id);
117 : :
118 : : // node back to HIR
119 : 31922 : HirId ref;
120 : 31922 : bool ok = mappings->lookup_node_to_hir (ref_node_id, &ref);
121 : 31922 : rust_assert (ok);
122 : :
123 : : // it must resolve to some kind of HIR::Item or HIR::InheritImplItem
124 : 31922 : HIR::Item *resolved_item = mappings->lookup_hir_item (ref);
125 : 31922 : if (resolved_item != nullptr)
126 : : {
127 : 4673 : mark_hir_id (resolved_item->get_mappings ().get_hirid ());
128 : : }
129 : : else
130 : : {
131 : 27249 : HirId parent_impl_id = UNKNOWN_HIRID;
132 : 27249 : HIR::ImplItem *resolved_item
133 : 27249 : = mappings->lookup_hir_implitem (ref, &parent_impl_id);
134 : 27249 : if (resolved_item != nullptr)
135 : : {
136 : 405 : mark_hir_id (resolved_item->get_impl_mappings ().get_hirid ());
137 : : }
138 : : }
139 : 31922 : }
140 : :
141 : : void
142 : 791 : MarkLive::visit (HIR::MethodCallExpr &expr)
143 : : {
144 : 791 : expr.get_receiver ()->accept_vis (*this);
145 : 791 : visit_path_segment (expr.get_method_name ());
146 : 1050 : for (auto &argument : expr.get_arguments ())
147 : 259 : argument->accept_vis (*this);
148 : :
149 : : // Trying to find the method definition and mark it alive.
150 : 791 : NodeId ast_node_id = expr.get_mappings ().get_nodeid ();
151 : 791 : NodeId ref_node_id = UNKNOWN_NODEID;
152 : 791 : find_ref_node_id (ast_node_id, ref_node_id);
153 : :
154 : : // node back to HIR
155 : 791 : HirId ref;
156 : 791 : bool ok = mappings->lookup_node_to_hir (ref_node_id, &ref);
157 : 791 : rust_assert (ok);
158 : 791 : mark_hir_id (ref);
159 : 791 : }
160 : :
161 : : bool
162 : 34433 : MarkLive::visit_path_segment (HIR::PathExprSegment seg)
163 : : {
164 : 34433 : NodeId ast_node_id = seg.get_mappings ().get_nodeid ();
165 : 34433 : NodeId ref_node_id = UNKNOWN_NODEID;
166 : :
167 : : // There are two different kinds of segment for us.
168 : : // 1. function segment
169 : : // like the symbol "foo" in expression `foo()`.
170 : : // 2. type segment
171 : : // like the symbol "Foo" in expression `Foo{a: 1, b: 2}`
172 : : //
173 : : // We should mark them alive all and ignoring other kind of segments.
174 : : // If the segment we dont care then just return false is fine
175 : 34433 : if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
176 : : {
177 : 3816 : if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id))
178 : : return false;
179 : : }
180 : 33122 : HirId ref;
181 : 33122 : bool ok = mappings->lookup_node_to_hir (ref_node_id, &ref);
182 : 33122 : rust_assert (ok);
183 : 33122 : mark_hir_id (ref);
184 : 33122 : return true;
185 : : }
186 : :
187 : : void
188 : 2854 : MarkLive::visit (HIR::FieldAccessExpr &expr)
189 : : {
190 : : // visit receiver at first
191 : 2854 : expr.get_receiver_expr ()->accept_vis (*this);
192 : :
193 : : // resolve the receiver back to ADT type
194 : 2854 : TyTy::BaseType *receiver = nullptr;
195 : 2854 : if (!tyctx->lookup_type (
196 : 2854 : expr.get_receiver_expr ()->get_mappings ().get_hirid (), &receiver))
197 : : {
198 : 0 : rust_error_at (expr.get_receiver_expr ()->get_locus (),
199 : : "unresolved type for receiver");
200 : : }
201 : :
202 : 2854 : TyTy::ADTType *adt = nullptr;
203 : 2854 : if (receiver->get_kind () == TyTy::TypeKind::ADT)
204 : : {
205 : 2794 : adt = static_cast<TyTy::ADTType *> (receiver);
206 : : }
207 : 60 : else if (receiver->get_kind () == TyTy::TypeKind::REF)
208 : : {
209 : 60 : TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (receiver);
210 : 60 : TyTy::BaseType *b = r->get_base ();
211 : 60 : rust_assert (b->get_kind () == TyTy::TypeKind::ADT);
212 : :
213 : : adt = static_cast<TyTy::ADTType *> (b);
214 : : }
215 : :
216 : 2794 : rust_assert (adt != nullptr);
217 : 2854 : rust_assert (!adt->is_enum ());
218 : 2854 : rust_assert (adt->number_of_variants () == 1);
219 : :
220 : 2854 : TyTy::VariantDef *variant = adt->get_variants ().at (0);
221 : :
222 : : // get the field index
223 : 2854 : size_t index;
224 : 2854 : TyTy::StructFieldType *field;
225 : 2854 : bool ok = variant->lookup_field (expr.get_field_name ().as_string (), &field,
226 : : &index);
227 : 2854 : rust_assert (ok);
228 : 2854 : if (index >= variant->num_fields ())
229 : : {
230 : 0 : rust_error_at (expr.get_receiver_expr ()->get_locus (),
231 : : "cannot access struct %s by index: %lu",
232 : 0 : adt->get_name ().c_str (), (unsigned long) index);
233 : 0 : return;
234 : : }
235 : :
236 : : // get the field hir id
237 : 2854 : HirId field_id = field->get_ref ();
238 : 2854 : mark_hir_id (field_id);
239 : : }
240 : :
241 : : void
242 : 509 : MarkLive::visit (HIR::TupleIndexExpr &expr)
243 : : {
244 : : // TODO: unused tuple field detection
245 : 509 : expr.get_tuple_expr ()->accept_vis (*this);
246 : 509 : }
247 : :
248 : : void
249 : 14 : MarkLive::visit (HIR::TypeAlias &alias)
250 : : {
251 : 14 : NodeId ast_node_id;
252 : 14 : resolver->lookup_resolved_type (
253 : 14 : alias.get_type_aliased ()->get_mappings ().get_nodeid (), &ast_node_id);
254 : 14 : HirId hir_id;
255 : 14 : bool ok = mappings->lookup_node_to_hir (ast_node_id, &hir_id);
256 : 14 : rust_assert (ok);
257 : 14 : mark_hir_id (hir_id);
258 : 14 : }
259 : :
260 : : void
261 : 41859 : MarkLive::mark_hir_id (HirId id)
262 : : {
263 : 41859 : if (scannedSymbols.find (id) == scannedSymbols.end ())
264 : : {
265 : 24973 : worklist.push_back (id);
266 : : }
267 : 41859 : liveSymbols.emplace (id);
268 : 41859 : }
269 : :
270 : : void
271 : 32713 : MarkLive::find_ref_node_id (NodeId ast_node_id, NodeId &ref_node_id)
272 : : {
273 : 32713 : if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
274 : : {
275 : 1777 : if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id))
276 : : {
277 : 2 : bool ok = resolver->lookup_resolved_misc (ast_node_id, &ref_node_id);
278 : 2 : rust_assert (ok);
279 : : }
280 : : }
281 : 32713 : }
282 : :
283 : : } // namespace Analysis
284 : : } // namespace Rust
|