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