Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 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-early-name-resolver-2.0.h"
20 : : #include "rust-ast-full.h"
21 : : #include "rust-diagnostics.h"
22 : : #include "rust-toplevel-name-resolver-2.0.h"
23 : : #include "rust-attributes.h"
24 : : #include "rust-finalize-imports-2.0.h"
25 : : #include "rust-attribute-values.h"
26 : :
27 : : namespace Rust {
28 : : namespace Resolver2_0 {
29 : :
30 : 2857 : Early::Early (NameResolutionContext &ctx)
31 : 2857 : : DefaultResolver (ctx), toplevel (TopLevel (ctx)), dirty (false)
32 : 2857 : {}
33 : :
34 : : void
35 : 1386 : Early::insert_once (AST::MacroInvocation &invocation, NodeId resolved)
36 : : {
37 : : // TODO: Should we use `ctx.mark_resolved()`?
38 : 1386 : auto definition = ctx.mappings.lookup_macro_def (resolved);
39 : :
40 : 1386 : if (!ctx.mappings.lookup_macro_invocation (invocation))
41 : 1386 : ctx.mappings.insert_macro_invocation (invocation, definition.value ());
42 : 1386 : }
43 : :
44 : : void
45 : 1529 : Early::insert_once (AST::MacroRulesDefinition &def)
46 : : {
47 : : // TODO: Should we use `ctx.mark_resolved()`?
48 : 1529 : if (!ctx.mappings.lookup_macro_def (def.get_node_id ()))
49 : 1 : ctx.mappings.insert_macro_def (&def);
50 : 1529 : }
51 : :
52 : : void
53 : 2857 : Early::go (AST::Crate &crate)
54 : : {
55 : : // First we go through TopLevel resolution to get all our declared items
56 : 2857 : toplevel.go (crate);
57 : :
58 : : // We start with resolving the list of imports that `TopLevel` has built for
59 : : // us
60 : :
61 : 2857 : dirty = toplevel.is_dirty ();
62 : : // We now proceed with resolving macros, which can be nested in almost any
63 : : // items
64 : 2857 : textual_scope.push ();
65 : 11502 : for (auto &item : crate.items)
66 : 8645 : item->accept_vis (*this);
67 : 2857 : textual_scope.pop ();
68 : 2857 : }
69 : :
70 : : bool
71 : 12 : Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob)
72 : : {
73 : 12 : auto resolved
74 : 12 : = ctx.resolve_path (glob.to_resolve.get_segments (), Namespace::Types);
75 : 12 : if (!resolved.has_value ())
76 : : return false;
77 : :
78 : 10 : auto result
79 : 10 : = Analysis::Mappings::get ().lookup_ast_module (resolved->get_node_id ());
80 : 10 : if (!result)
81 : : return false;
82 : :
83 : : // here, we insert the module's NodeId into the import_mappings and will look
84 : : // up the module proper in `FinalizeImports`
85 : : // The namespace does not matter here since we are dealing with a glob
86 : : // TODO: Ugly
87 : 20 : import_mappings.insert (use_dec_id,
88 : 10 : ImportPair (std::move (glob),
89 : 30 : ImportData::Glob (*resolved)));
90 : :
91 : 10 : return true;
92 : 12 : }
93 : :
94 : : bool
95 : 0 : Early::resolve_simple_import (NodeId use_dec_id, TopLevel::ImportKind &&import)
96 : : {
97 : 0 : auto definitions = resolve_path_in_all_ns (import.to_resolve);
98 : :
99 : : // if we've found at least one definition, then we're good
100 : 0 : if (definitions.empty ())
101 : : return false;
102 : :
103 : 0 : auto &imports = import_mappings.new_or_access (use_dec_id);
104 : :
105 : 0 : imports.emplace_back (
106 : 0 : ImportPair (std::move (import),
107 : 0 : ImportData::Simple (std::move (definitions))));
108 : :
109 : 0 : return true;
110 : 0 : }
111 : :
112 : : bool
113 : 238 : Early::resolve_rebind_import (NodeId use_dec_id,
114 : : TopLevel::ImportKind &&rebind_import)
115 : : {
116 : 238 : auto definitions = resolve_path_in_all_ns (rebind_import.to_resolve);
117 : :
118 : : // if we've found at least one definition, then we're good
119 : 238 : if (definitions.empty ())
120 : : return false;
121 : :
122 : 219 : auto &imports = import_mappings.new_or_access (use_dec_id);
123 : :
124 : 219 : imports.emplace_back (
125 : 219 : ImportPair (std::move (rebind_import),
126 : 438 : ImportData::Rebind (std::move (definitions))));
127 : :
128 : 219 : return true;
129 : 238 : }
130 : :
131 : : void
132 : 163 : Early::build_import_mapping (
133 : : std::pair<NodeId, std::vector<TopLevel::ImportKind>> &&use_import)
134 : : {
135 : 163 : auto found = false;
136 : 163 : auto use_dec_id = use_import.first;
137 : :
138 : 413 : for (auto &&import : use_import.second)
139 : : {
140 : : // We create a copy of the path in case of errors, since the `import` will
141 : : // be moved into the newly created import mappings
142 : 250 : auto path = import.to_resolve;
143 : :
144 : 250 : switch (import.kind)
145 : : {
146 : 12 : case TopLevel::ImportKind::Kind::Glob:
147 : 12 : found = resolve_glob_import (use_dec_id, std::move (import));
148 : 12 : break;
149 : 0 : case TopLevel::ImportKind::Kind::Simple:
150 : 0 : found = resolve_simple_import (use_dec_id, std::move (import));
151 : 0 : break;
152 : 238 : case TopLevel::ImportKind::Kind::Rebind:
153 : 238 : found = resolve_rebind_import (use_dec_id, std::move (import));
154 : 238 : break;
155 : : }
156 : :
157 : 250 : if (!found)
158 : 42 : collect_error (Error (path.get_final_segment ().get_locus (),
159 : : ErrorCode::E0433, "unresolved import %qs",
160 : 42 : path.as_string ().c_str ()));
161 : 250 : }
162 : 163 : }
163 : :
164 : : void
165 : 10508 : Early::TextualScope::push ()
166 : : {
167 : : // push a new empty scope
168 : 10508 : scopes.emplace_back ();
169 : 10508 : }
170 : :
171 : : void
172 : 10508 : Early::TextualScope::pop ()
173 : : {
174 : 10508 : rust_assert (!scopes.empty ());
175 : :
176 : 10508 : scopes.pop_back ();
177 : 10508 : }
178 : :
179 : : void
180 : 1529 : Early::TextualScope::insert (std::string name, NodeId id)
181 : : {
182 : 1529 : rust_assert (!scopes.empty ());
183 : :
184 : : // we can ignore the return value as we always want the latest defined macro
185 : : // to shadow a previous one - so if two macros have the same name and get
186 : : // inserted with the same key, it's not a bug
187 : 1529 : scopes.back ().insert ({name, id});
188 : 1529 : }
189 : :
190 : : tl::optional<NodeId>
191 : 1392 : Early::TextualScope::get (const std::string &name)
192 : : {
193 : 2683 : for (auto iterator = scopes.rbegin (); iterator != scopes.rend (); iterator++)
194 : : {
195 : 2655 : auto scope = *iterator;
196 : 2655 : auto found = scope.find (name);
197 : 2655 : if (found != scope.end ())
198 : 1364 : return found->second;
199 : 2655 : }
200 : :
201 : 28 : return tl::nullopt;
202 : : }
203 : :
204 : : void
205 : 1529 : Early::visit (AST::MacroRulesDefinition &def)
206 : : {
207 : 1529 : DefaultResolver::visit (def);
208 : :
209 : 1529 : textual_scope.insert (def.get_rule_name ().as_string (), def.get_node_id ());
210 : 1529 : insert_once (def);
211 : 1529 : }
212 : :
213 : : void
214 : 7099 : Early::visit (AST::BlockExpr &block)
215 : : {
216 : 7099 : textual_scope.push ();
217 : :
218 : 7099 : DefaultResolver::visit (block);
219 : :
220 : 7099 : textual_scope.pop ();
221 : 7099 : }
222 : :
223 : : void
224 : 570 : Early::visit (AST::Module &module)
225 : : {
226 : 570 : bool is_macro_use = false;
227 : :
228 : 627 : for (const auto &attr : module.get_outer_attrs ())
229 : : {
230 : 75 : if (attr.get_path ().as_string () == Values::Attributes::MACRO_USE)
231 : : {
232 : : is_macro_use = true;
233 : : break;
234 : : }
235 : : }
236 : :
237 : 570 : if (!is_macro_use)
238 : 552 : textual_scope.push ();
239 : :
240 : 570 : DefaultResolver::visit (module);
241 : :
242 : 570 : if (!is_macro_use)
243 : 552 : textual_scope.pop ();
244 : 570 : }
245 : :
246 : : void
247 : 1418 : Early::visit (AST::MacroInvocation &invoc)
248 : : {
249 : 1418 : auto path = invoc.get_invoc_data ().get_path ();
250 : :
251 : 1418 : if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin)
252 : 17 : for (auto &pending_invoc : invoc.get_pending_eager_invocations ())
253 : 10 : pending_invoc->accept_vis (*this);
254 : :
255 : : // When a macro is invoked by an unqualified identifier (not part of a
256 : : // multi-part path), it is first looked up in textual scoping. If this does
257 : : // not yield any results, then it is looked up in path-based scoping. If the
258 : : // macro's name is qualified with a path, then it is only looked up in
259 : : // path-based scoping.
260 : :
261 : : // https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope
262 : :
263 : 1418 : tl::optional<Rib::Definition> definition = tl::nullopt;
264 : 1418 : if (path.get_segments ().size () == 1)
265 : 1392 : definition
266 : 1392 : = textual_scope.get (path.get_final_segment ().as_string ())
267 : 4120 : .map ([] (NodeId id) { return Rib::Definition::NonShadowable (id); });
268 : :
269 : : // we won't have changed `definition` from `nullopt` if there are more
270 : : // than one segments in our path
271 : 1418 : if (!definition.has_value ())
272 : 76 : definition = ctx.resolve_path (path.get_segments (), Namespace::Macros);
273 : :
274 : : // if the definition still does not have a value, then it's an error
275 : 1418 : if (!definition.has_value ())
276 : : {
277 : 32 : collect_error (Error (invoc.get_locus (), ErrorCode::E0433,
278 : : "could not resolve macro invocation %qs",
279 : 32 : path.as_string ().c_str ()));
280 : 32 : return;
281 : : }
282 : :
283 : 1386 : insert_once (invoc, definition->get_node_id ());
284 : :
285 : : // now do we need to keep mappings or something? or insert "uses" into our
286 : : // ForeverStack? can we do that? are mappings simpler?
287 : 1386 : auto &mappings = Analysis::Mappings::get ();
288 : 1386 : auto rules_def = mappings.lookup_macro_def (definition->get_node_id ());
289 : :
290 : : // Macro definition not found, maybe it is not expanded yet.
291 : 1386 : if (!rules_def)
292 : : return;
293 : :
294 : 1386 : if (mappings.lookup_macro_invocation (invoc))
295 : : return;
296 : :
297 : 0 : mappings.insert_macro_invocation (invoc, rules_def.value ());
298 : 1418 : }
299 : :
300 : : void
301 : 7117 : Early::visit_attributes (std::vector<AST::Attribute> &attrs)
302 : : {
303 : 7117 : auto &mappings = Analysis::Mappings::get ();
304 : :
305 : 8398 : for (auto &attr : attrs)
306 : : {
307 : 1281 : auto name = attr.get_path ().get_segments ().at (0).get_segment_name ();
308 : :
309 : 1281 : if (attr.is_derive ())
310 : : {
311 : 18 : auto traits = attr.get_traits_to_derive ();
312 : 37 : for (auto &trait : traits)
313 : : {
314 : 38 : auto definition = ctx.resolve_path (trait.get ().get_segments (),
315 : 19 : Namespace::Macros);
316 : 19 : if (!definition.has_value ())
317 : : {
318 : : // FIXME: Change to proper error message
319 : 38 : collect_error (Error (trait.get ().get_locus (),
320 : : "could not resolve trait %qs",
321 : 19 : trait.get ().as_string ().c_str ()));
322 : 19 : continue;
323 : : }
324 : :
325 : 0 : auto pm_def = mappings.lookup_derive_proc_macro_def (
326 : : definition->get_node_id ());
327 : :
328 : 0 : if (pm_def.has_value ())
329 : 0 : mappings.insert_derive_proc_macro_invocation (trait,
330 : 0 : pm_def.value ());
331 : 19 : }
332 : 18 : }
333 : 2526 : else if (Analysis::BuiltinAttributeMappings::get ()
334 : 1263 : ->lookup_builtin (name)
335 : 1263 : .is_error ()) // Do not resolve builtins
336 : : {
337 : 0 : auto definition = ctx.resolve_path (attr.get_path ().get_segments (),
338 : 0 : Namespace::Macros);
339 : 0 : if (!definition.has_value ())
340 : : {
341 : : // FIXME: Change to proper error message
342 : 0 : collect_error (
343 : 0 : Error (attr.get_locus (),
344 : 0 : "could not resolve attribute macro invocation"));
345 : 0 : return;
346 : : }
347 : 0 : auto pm_def = mappings.lookup_attribute_proc_macro_def (
348 : : definition->get_node_id ());
349 : :
350 : 0 : rust_assert (pm_def.has_value ());
351 : :
352 : 0 : mappings.insert_attribute_proc_macro_invocation (attr.get_path (),
353 : 0 : pm_def.value ());
354 : 0 : }
355 : 1281 : }
356 : : }
357 : :
358 : : void
359 : 6550 : Early::visit (AST::Function &fn)
360 : : {
361 : 6550 : visit_attributes (fn.get_outer_attrs ());
362 : 6550 : DefaultResolver::visit (fn);
363 : 6550 : }
364 : :
365 : : void
366 : 567 : Early::visit (AST::StructStruct &s)
367 : : {
368 : 567 : visit_attributes (s.get_outer_attrs ());
369 : 567 : DefaultResolver::visit (s);
370 : 567 : }
371 : :
372 : : void
373 : 0 : Early::finalize_simple_import (const Early::ImportPair &mapping)
374 : : {
375 : : // FIXME: We probably need to store namespace information
376 : :
377 : 0 : auto locus = mapping.import_kind.to_resolve.get_locus ();
378 : 0 : auto data = mapping.data;
379 : 0 : auto identifier
380 : 0 : = mapping.import_kind.to_resolve.get_final_segment ().get_segment_name ();
381 : :
382 : 0 : for (auto &&definition : data.definitions ())
383 : 0 : toplevel
384 : 0 : .insert_or_error_out (
385 : 0 : identifier, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
386 : 0 : }
387 : :
388 : : void
389 : 10 : Early::finalize_glob_import (NameResolutionContext &ctx,
390 : : const Early::ImportPair &mapping)
391 : : {
392 : 20 : auto module = Analysis::Mappings::get ().lookup_ast_module (
393 : 20 : mapping.data.module ().get_node_id ());
394 : 10 : rust_assert (module);
395 : :
396 : 10 : GlobbingVisitor glob_visitor (ctx);
397 : 10 : glob_visitor.go (module.value ());
398 : 10 : }
399 : :
400 : : void
401 : 219 : Early::finalize_rebind_import (const Early::ImportPair &mapping)
402 : : {
403 : : // We can fetch the value here as `resolve_rebind` will only be called on
404 : : // imports of the right kind
405 : 219 : auto &path = mapping.import_kind.to_resolve;
406 : 219 : auto &rebind = mapping.import_kind.rebind.value ();
407 : 219 : auto data = mapping.data;
408 : :
409 : 219 : location_t locus = UNKNOWN_LOCATION;
410 : 219 : std::string declared_name;
411 : :
412 : : // FIXME: This needs to be done in `FinalizeImports`
413 : 219 : switch (rebind.get_new_bind_type ())
414 : : {
415 : 6 : case AST::UseTreeRebind::NewBindType::IDENTIFIER:
416 : 6 : declared_name = rebind.get_identifier ().as_string ();
417 : 6 : locus = rebind.get_identifier ().get_locus ();
418 : 6 : break;
419 : 213 : case AST::UseTreeRebind::NewBindType::NONE: {
420 : 213 : const auto &segments = path.get_segments ();
421 : : // We don't want to insert `self` with `use module::self`
422 : 213 : if (path.get_final_segment ().is_lower_self_seg ())
423 : : {
424 : 38 : rust_assert (segments.size () > 1);
425 : 38 : declared_name = segments[segments.size () - 2].as_string ();
426 : : }
427 : : else
428 : 175 : declared_name = path.get_final_segment ().as_string ();
429 : 213 : locus = path.get_final_segment ().get_locus ();
430 : 213 : break;
431 : : }
432 : 0 : case AST::UseTreeRebind::NewBindType::WILDCARD:
433 : 0 : rust_unreachable ();
434 : 219 : break;
435 : : }
436 : :
437 : 469 : for (auto &&definition : data.definitions ())
438 : 250 : toplevel.insert_or_error_out (
439 : 719 : declared_name, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
440 : 219 : }
441 : :
442 : : void
443 : 163 : Early::visit (AST::UseDeclaration &decl)
444 : : {
445 : 163 : auto &imports = toplevel.get_imports_to_resolve ();
446 : 163 : auto current_import = imports.find (decl.get_node_id ());
447 : 163 : if (current_import != imports.end ())
448 : : {
449 : 163 : build_import_mapping (*current_import);
450 : : }
451 : :
452 : : // Once this is done, we finalize their resolution
453 : 392 : for (const auto &mapping : import_mappings.get (decl.get_node_id ()))
454 : 229 : switch (mapping.import_kind.kind)
455 : : {
456 : 10 : case TopLevel::ImportKind::Kind::Glob:
457 : 10 : finalize_glob_import (ctx, mapping);
458 : 10 : break;
459 : 0 : case TopLevel::ImportKind::Kind::Simple:
460 : 0 : finalize_simple_import (mapping);
461 : 0 : break;
462 : 219 : case TopLevel::ImportKind::Kind::Rebind:
463 : 219 : finalize_rebind_import (mapping);
464 : 219 : break;
465 : : }
466 : :
467 : 163 : DefaultResolver::visit (decl);
468 : 163 : }
469 : :
470 : : } // namespace Resolver2_0
471 : : } // namespace Rust
|