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