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