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 : 9996 : Early::Early (NameResolutionContext &ctx)
34 : 9996 : : DefaultResolver (ctx), toplevel (TopLevel (ctx)), dirty (false)
35 : 9996 : {}
36 : :
37 : : void
38 : 2751 : Early::insert_once (AST::MacroInvocation &invocation, NodeId resolved)
39 : : {
40 : : // TODO: Should we use `ctx.mark_resolved()`?
41 : 2751 : auto definition = ctx.mappings.lookup_macro_def (resolved);
42 : :
43 : 2751 : if (!ctx.mappings.lookup_macro_invocation (invocation))
44 : 2751 : ctx.mappings.insert_macro_invocation (invocation, definition.value ());
45 : 2751 : }
46 : :
47 : : void
48 : 3724 : Early::insert_once (AST::MacroRulesDefinition &def)
49 : : {
50 : : // TODO: Should we use `ctx.mark_resolved()`?
51 : 3724 : if (!ctx.mappings.lookup_macro_def (def.get_node_id ()))
52 : 1 : ctx.mappings.insert_macro_def (&def);
53 : 3724 : }
54 : :
55 : : void
56 : 9996 : Early::go (AST::Crate &crate)
57 : : {
58 : : // First we go through TopLevel resolution to get all our declared items
59 : 9996 : toplevel.go (crate);
60 : :
61 : : // We start with resolving the list of imports that `TopLevel` has built for
62 : : // us
63 : :
64 : 9996 : dirty = toplevel.is_dirty ();
65 : : // We now proceed with resolving macros, which can be nested in almost any
66 : : // items
67 : 9996 : textual_scope.push ();
68 : :
69 : 9996 : visit (crate);
70 : :
71 : 9996 : textual_scope.pop ();
72 : 9996 : }
73 : :
74 : : bool
75 : 17 : Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob)
76 : : {
77 : 17 : auto resolved = ctx.resolve_path (glob.to_resolve, Namespace::Types);
78 : 17 : if (!resolved.has_value ())
79 : : return false;
80 : :
81 : 16 : auto result = Analysis::Mappings::get ().lookup_glob_container (
82 : : resolved->get_node_id ());
83 : :
84 : 16 : 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 : 32 : import_mappings.insert (use_dec_id,
92 : 16 : ImportPair (std::move (glob),
93 : 48 : ImportData::Glob (*resolved)));
94 : :
95 : 16 : return true;
96 : 17 : }
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 : 2968 : Early::resolve_rebind_import (NodeId use_dec_id,
118 : : TopLevel::ImportKind &&rebind_import)
119 : : {
120 : 2968 : 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 : 2968 : if (definitions.empty ())
124 : : return false;
125 : :
126 : 2957 : auto &imports = import_mappings.new_or_access (use_dec_id);
127 : :
128 : 2957 : imports.emplace_back (
129 : 2957 : ImportPair (std::move (rebind_import),
130 : 5914 : ImportData::Rebind (std::move (definitions))));
131 : :
132 : 2957 : return true;
133 : 2968 : }
134 : :
135 : : void
136 : 1769 : Early::build_import_mapping (
137 : : std::pair<NodeId, std::vector<TopLevel::ImportKind>> &&use_import)
138 : : {
139 : 1769 : auto found = false;
140 : 1769 : auto use_dec_id = use_import.first;
141 : :
142 : 4754 : 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 : 2985 : auto path = import.to_resolve;
147 : :
148 : : // used to skip the "unresolved import" error
149 : : // if we output other errors during resolution
150 : 2985 : size_t old_error_count = macro_resolve_errors.size ();
151 : :
152 : 2985 : switch (import.kind)
153 : : {
154 : 17 : case TopLevel::ImportKind::Kind::Glob:
155 : 17 : found = resolve_glob_import (use_dec_id, std::move (import));
156 : 17 : break;
157 : 0 : case TopLevel::ImportKind::Kind::Simple:
158 : 0 : found = resolve_simple_import (use_dec_id, std::move (import));
159 : 0 : break;
160 : 2968 : case TopLevel::ImportKind::Kind::Rebind:
161 : 2968 : found = resolve_rebind_import (use_dec_id, std::move (import));
162 : 2968 : break;
163 : : }
164 : :
165 : 2985 : if (!found && old_error_count == macro_resolve_errors.size ())
166 : 30 : collect_error (Error (path.get_final_segment ().get_locus (),
167 : : ErrorCode::E0433, "unresolved import %qs",
168 : 20 : path.as_string ().c_str ()));
169 : 2985 : }
170 : 1769 : }
171 : :
172 : : void
173 : 64586 : Early::TextualScope::push ()
174 : : {
175 : : // push a new empty scope
176 : 64586 : scopes.emplace_back ();
177 : 64586 : }
178 : :
179 : : void
180 : 64586 : Early::TextualScope::pop ()
181 : : {
182 : 64586 : rust_assert (!scopes.empty ());
183 : :
184 : 64586 : scopes.pop_back ();
185 : 64586 : }
186 : :
187 : : void
188 : 3724 : Early::TextualScope::insert (std::string name, NodeId id)
189 : : {
190 : 3724 : 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 : 7448 : scopes.back ().insert ({name, id});
196 : 3724 : }
197 : :
198 : : tl::optional<NodeId>
199 : 2779 : Early::TextualScope::get (const std::string &name)
200 : : {
201 : 5435 : for (auto iterator = scopes.rbegin (); iterator != scopes.rend (); iterator++)
202 : : {
203 : 5394 : auto scope = *iterator;
204 : 5394 : auto found = scope.find (name);
205 : 5394 : if (found != scope.end ())
206 : 2738 : return found->second;
207 : 5394 : }
208 : :
209 : 41 : return tl::nullopt;
210 : : }
211 : :
212 : : void
213 : 3724 : Early::visit (AST::MacroRulesDefinition &def)
214 : : {
215 : 3724 : DefaultResolver::visit (def);
216 : :
217 : 7448 : textual_scope.insert (def.get_rule_name ().as_string (), def.get_node_id ());
218 : 3724 : insert_once (def);
219 : 3724 : }
220 : :
221 : : void
222 : 51429 : Early::visit (AST::BlockExpr &block)
223 : : {
224 : 51429 : textual_scope.push ();
225 : :
226 : 51429 : DefaultResolver::visit (block);
227 : :
228 : 51429 : textual_scope.pop ();
229 : 51429 : }
230 : :
231 : : void
232 : 3192 : Early::visit (AST::Module &module)
233 : : {
234 : 3192 : bool is_macro_use = false;
235 : :
236 : 3431 : for (const auto &attr : module.get_outer_attrs ())
237 : : {
238 : 270 : if (attr.get_path ().as_string () == Values::Attributes::MACRO_USE)
239 : : {
240 : : is_macro_use = true;
241 : : break;
242 : : }
243 : : }
244 : :
245 : 3192 : if (!is_macro_use)
246 : 3161 : textual_scope.push ();
247 : :
248 : 3192 : DefaultResolver::visit (module);
249 : :
250 : 3192 : if (!is_macro_use)
251 : 3161 : textual_scope.pop ();
252 : 3192 : }
253 : :
254 : : void
255 : 2791 : Early::visit (AST::MacroInvocation &invoc)
256 : : {
257 : 2791 : 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 : 2791 : auto resolve_offset_of
262 : 2791 : = flag_assume_builtin_offset_of && (path.as_string () == "offset_of");
263 : :
264 : 2791 : if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin)
265 : 87 : for (auto &pending_invoc : invoc.get_pending_eager_invocations ())
266 : 45 : 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 : 2791 : tl::optional<Rib::Definition> definition = tl::nullopt;
277 : 2791 : if (path.get_segments ().size () == 1)
278 : 2779 : definition
279 : 2779 : = textual_scope.get (path.get_final_segment ().as_string ())
280 : 8255 : .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 : 2791 : if (!definition.has_value ())
285 : 66 : 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 : 2791 : if (!definition.has_value ())
290 : : {
291 : 40 : if (!resolve_offset_of)
292 : 22 : collect_error (Error (invoc.get_locus (), ErrorCode::E0433,
293 : : "could not resolve macro invocation %qs",
294 : 44 : path.as_string ().c_str ()));
295 : 40 : return;
296 : : }
297 : :
298 : 2751 : 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 : 2751 : auto &mappings = Analysis::Mappings::get ();
303 : 2751 : auto rules_def = mappings.lookup_macro_def (definition->get_node_id ());
304 : :
305 : : // Macro definition not found, maybe it is not expanded yet.
306 : 2751 : if (!rules_def)
307 : : return;
308 : :
309 : 2751 : if (mappings.lookup_macro_invocation (invoc))
310 : : return;
311 : :
312 : 0 : mappings.insert_macro_invocation (invoc, rules_def.value ());
313 : 2791 : }
314 : :
315 : : void
316 : 46607 : Early::visit_attributes (std::vector<AST::Attribute> &attrs)
317 : : {
318 : 46607 : auto &mappings = Analysis::Mappings::get ();
319 : :
320 : 75155 : for (auto &attr : attrs)
321 : : {
322 : 28549 : auto name = attr.get_path ().get_segments ().at (0).get_segment_name ();
323 : :
324 : 28549 : if (attr.is_derive ())
325 : : {
326 : 96 : auto traits = attr.get_traits_to_derive ();
327 : 291 : for (auto &trait : traits)
328 : : {
329 : 195 : auto definition
330 : 195 : = ctx.resolve_path (trait.get (), Namespace::Macros);
331 : 195 : if (!definition.has_value ())
332 : : {
333 : : // FIXME: Change to proper error message
334 : 390 : collect_error (Error (trait.get ().get_locus (),
335 : : "could not resolve trait %qs",
336 : 195 : trait.get ().as_string ().c_str ()));
337 : 195 : continue;
338 : : }
339 : :
340 : 0 : auto pm_def = mappings.lookup_derive_proc_macro_def (
341 : : definition->get_node_id ());
342 : :
343 : 0 : if (pm_def.has_value ())
344 : 0 : mappings.insert_derive_proc_macro_invocation (trait,
345 : 0 : pm_def.value ());
346 : 195 : }
347 : 96 : }
348 : 56906 : else if (Analysis::BuiltinAttributeMappings::get ()
349 : 28453 : ->lookup_builtin (name)
350 : 28453 : .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 : 28549 : }
372 : : }
373 : :
374 : : void
375 : 43231 : Early::visit (AST::Function &fn)
376 : : {
377 : 43231 : visit_attributes (fn.get_outer_attrs ());
378 : 43231 : DefaultResolver::visit (fn);
379 : 43231 : }
380 : :
381 : : void
382 : 3376 : Early::visit (AST::StructStruct &s)
383 : : {
384 : 3376 : visit_attributes (s.get_outer_attrs ());
385 : 3376 : DefaultResolver::visit (s);
386 : 3376 : }
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 : 16 : Early::finalize_glob_import (NameResolutionContext &ctx,
406 : : const Early::ImportPair &mapping)
407 : : {
408 : 32 : auto container = Analysis::Mappings::get ().lookup_glob_container (
409 : 32 : mapping.data.container ().get_node_id ());
410 : :
411 : 16 : rust_assert (container);
412 : :
413 : 16 : GlobbingVisitor (ctx).go (container.value ());
414 : 16 : }
415 : :
416 : : void
417 : 2957 : 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 : 2957 : auto &path = mapping.import_kind.to_resolve;
422 : 2957 : auto &rebind = mapping.import_kind.rebind.value ();
423 : 2957 : auto data = mapping.data;
424 : :
425 : 2957 : location_t locus = UNKNOWN_LOCATION;
426 : 2957 : std::string declared_name;
427 : :
428 : : // FIXME: This needs to be done in `FinalizeImports`
429 : 2957 : switch (rebind.get_new_bind_type ())
430 : : {
431 : 4 : case AST::UseTreeRebind::NewBindType::IDENTIFIER:
432 : 4 : declared_name = rebind.get_identifier ().as_string ();
433 : 4 : locus = rebind.get_identifier ().get_locus ();
434 : 4 : break;
435 : 2953 : case AST::UseTreeRebind::NewBindType::NONE:
436 : 2953 : {
437 : 2953 : const auto &segments = path.get_segments ();
438 : : // We don't want to insert `self` with `use module::self`
439 : 2953 : if (path.get_final_segment ().is_lower_self_seg ())
440 : : {
441 : 204 : rust_assert (segments.size () > 1);
442 : 204 : declared_name = segments[segments.size () - 2].as_string ();
443 : : }
444 : : else
445 : 2749 : declared_name = path.get_final_segment ().as_string ();
446 : 2953 : locus = path.get_final_segment ().get_locus ();
447 : 2953 : break;
448 : : }
449 : 0 : case AST::UseTreeRebind::NewBindType::WILDCARD:
450 : 0 : rust_unreachable ();
451 : 2957 : break;
452 : : }
453 : :
454 : 5967 : for (auto &&definition : data.definitions ())
455 : 3010 : toplevel.insert_or_error_out (
456 : 14997 : 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 */);
457 : 2957 : }
458 : :
459 : : void
460 : 1769 : Early::visit (AST::UseDeclaration &decl)
461 : : {
462 : 1769 : auto &imports = toplevel.get_imports_to_resolve ();
463 : 1769 : auto current_import = imports.find (decl.get_node_id ());
464 : 1769 : if (current_import != imports.end ())
465 : : {
466 : 1769 : build_import_mapping (*current_import);
467 : : }
468 : :
469 : : // Once this is done, we finalize their resolution
470 : 4742 : for (const auto &mapping : import_mappings.get (decl.get_node_id ()))
471 : 2973 : switch (mapping.import_kind.kind)
472 : : {
473 : 16 : case TopLevel::ImportKind::Kind::Glob:
474 : 16 : finalize_glob_import (ctx, mapping);
475 : 16 : break;
476 : 0 : case TopLevel::ImportKind::Kind::Simple:
477 : 0 : finalize_simple_import (mapping);
478 : 0 : break;
479 : 2957 : case TopLevel::ImportKind::Kind::Rebind:
480 : 2957 : finalize_rebind_import (mapping);
481 : 2957 : break;
482 : : }
483 : :
484 : 1769 : DefaultResolver::visit (decl);
485 : 1769 : }
486 : :
487 : : } // namespace Resolver2_0
488 : : } // namespace Rust
|