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