]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/rust/resolve/rust-early-name-resolver.cc
fc9a26ccac0ddd1bd9a72effd73c8ec060bb0180
[thirdparty/gcc.git] / gcc / rust / resolve / rust-early-name-resolver.cc
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.h"
20 #include "rust-pattern.h"
21 #include "rust-name-resolver.h"
22 #include "rust-macro-builtins.h"
23 #include "rust-attribute-values.h"
24
25 namespace Rust {
26 namespace Resolver {
27
28 // Check if a module contains the `#[macro_use]` attribute
29 static bool
30 is_macro_use_module (const AST::Module &mod)
31 {
32 for (const auto &attr : mod.get_outer_attrs ())
33 if (attr.get_path ().as_string () == Values::Attributes::MACRO_USE)
34 return true;
35
36 return false;
37 }
38
39 std::vector<std::unique_ptr<AST::Item>>
40 EarlyNameResolver::accumulate_escaped_macros (AST::Module &module)
41 {
42 if (!is_macro_use_module (module))
43 return {};
44
45 // Parse the module's items if they haven't been expanded and the file
46 // should be parsed (i.e isn't hidden behind an untrue or impossible cfg
47 // directive)
48 if (module.get_kind () == AST::Module::UNLOADED)
49 module.load_items ();
50
51 std::vector<std::unique_ptr<AST::Item>> escaped_macros;
52
53 scoped (module.get_node_id (), [&module, &escaped_macros, this] {
54 for (auto &item : module.get_items ())
55 {
56 if (item->get_item_kind () == AST::Item::Kind::Module)
57 {
58 auto &module = *static_cast<AST::Module *> (item.get ());
59 auto new_macros = accumulate_escaped_macros (module);
60
61 std::move (new_macros.begin (), new_macros.end (),
62 std::back_inserter (escaped_macros));
63
64 continue;
65 }
66
67 if (item->get_item_kind () == AST::Item::Kind::MacroRulesDefinition)
68 escaped_macros.emplace_back (item->clone_item ());
69 }
70 });
71
72 return escaped_macros;
73 }
74
75 EarlyNameResolver::EarlyNameResolver ()
76 : current_scope (UNKNOWN_NODEID), resolver (*Resolver::get ()),
77 mappings (Analysis::Mappings::get ())
78 {}
79
80 void
81 EarlyNameResolver::go (AST::Crate &crate)
82 {
83 visit (crate);
84 }
85
86 void
87 EarlyNameResolver::resolve_generic_args (AST::GenericArgs &generic_args)
88 {
89 for (auto &arg : generic_args.get_generic_args ())
90 arg.accept_vis (*this);
91
92 for (auto &arg : generic_args.get_binding_args ())
93 arg.get_type ().accept_vis (*this);
94 }
95
96 void
97 EarlyNameResolver::resolve_qualified_path_type (AST::QualifiedPathType &path)
98 {
99 path.get_type ().accept_vis (*this);
100
101 if (path.has_as_clause ())
102 path.get_as_type_path ().accept_vis (*this);
103 }
104
105 void
106 EarlyNameResolver::visit (AST::Crate &crate)
107 {
108 std::vector<std::unique_ptr<AST::Item>> new_items;
109 auto items = crate.take_items ();
110
111 scoped (crate.get_node_id (), [&items, &new_items, this] {
112 for (auto &&item : items)
113 {
114 auto new_macros = std::vector<std::unique_ptr<AST::Item>> ();
115
116 if (item->get_item_kind () == AST::Item::Kind::Module)
117 new_macros = accumulate_escaped_macros (
118 *static_cast<AST::Module *> (item.get ()));
119
120 new_items.emplace_back (std::move (item));
121 std::move (new_macros.begin (), new_macros.end (),
122 std::back_inserter (new_items));
123 }
124 });
125
126 crate.set_items (std::move (new_items));
127
128 scoped (crate.get_node_id (), [&crate, this] () {
129 for (auto &item : crate.items)
130 item->accept_vis (*this);
131 });
132 }
133
134 void
135 EarlyNameResolver::visit (AST::DelimTokenTree &)
136 {}
137
138 void
139 EarlyNameResolver::visit (AST::AttrInputMetaItemContainer &)
140 {}
141
142 void
143 EarlyNameResolver::visit (AST::IdentifierExpr &)
144 {}
145
146 void
147 EarlyNameResolver::visit (AST::LifetimeParam &)
148 {}
149
150 void
151 EarlyNameResolver::visit (AST::ConstGenericParam &)
152 {}
153
154 // FIXME: ARTHUR: Do we need to perform macro resolution for paths as well?
155 // std::arch::asm!()?
156 void
157 EarlyNameResolver::visit (AST::PathInExpression &path)
158 {
159 if (!path.is_lang_item ())
160 for (auto &segment : path.get_segments ())
161 if (segment.has_generic_args ())
162 resolve_generic_args (segment.get_generic_args ());
163 }
164
165 void
166 EarlyNameResolver::visit (AST::TypePathSegmentGeneric &segment)
167 {
168 if (segment.has_generic_args ())
169 resolve_generic_args (segment.get_generic_args ());
170 }
171
172 void
173 EarlyNameResolver::visit (AST::QualifiedPathInExpression &path)
174 {
175 resolve_qualified_path_type (path.get_qualified_path_type ());
176
177 for (auto &segment : path.get_segments ())
178 if (segment.has_generic_args ())
179 resolve_generic_args (segment.get_generic_args ());
180 }
181
182 void
183 EarlyNameResolver::visit (AST::QualifiedPathInType &path)
184 {
185 resolve_qualified_path_type (path.get_qualified_path_type ());
186
187 for (auto &segment : path.get_segments ())
188 segment->accept_vis (*this);
189 }
190
191 void
192 EarlyNameResolver::visit (AST::LiteralExpr &)
193 {}
194
195 void
196 EarlyNameResolver::visit (AST::AttrInputLiteral &)
197 {}
198
199 void
200 EarlyNameResolver::visit (AST::AttrInputMacro &)
201 {}
202
203 void
204 EarlyNameResolver::visit (AST::MetaItemLitExpr &)
205 {}
206
207 void
208 EarlyNameResolver::visit (AST::MetaItemPathLit &)
209 {}
210
211 void
212 EarlyNameResolver::visit (AST::StructExprStruct &)
213 {}
214
215 void
216 EarlyNameResolver::visit (AST::StructExprFieldIdentifier &)
217 {}
218
219 void
220 EarlyNameResolver::visit (AST::StructExprStructBase &)
221 {}
222
223 void
224 EarlyNameResolver::visit (AST::BlockExpr &expr)
225 {
226 scoped (expr.get_node_id (), [&expr, this] () {
227 for (auto &stmt : expr.get_statements ())
228 stmt->accept_vis (*this);
229
230 if (expr.has_tail_expr ())
231 expr.get_tail_expr ().accept_vis (*this);
232 });
233 }
234
235 void
236 EarlyNameResolver::visit (AST::ContinueExpr &)
237 {}
238
239 void
240 EarlyNameResolver::visit (AST::RangeFullExpr &)
241 {}
242
243 void
244 EarlyNameResolver::visit (AST::ForLoopExpr &expr)
245 {
246 scoped (expr.get_node_id (), [&expr, this] () {
247 expr.get_pattern ().accept_vis (*this);
248 expr.get_iterator_expr ().accept_vis (*this);
249 expr.get_loop_block ().accept_vis (*this);
250 });
251 }
252
253 void
254 EarlyNameResolver::visit (AST::IfLetExpr &expr)
255 {
256 expr.get_value_expr ().accept_vis (*this);
257
258 scoped (expr.get_node_id (),
259 [&expr, this] () { expr.get_if_block ().accept_vis (*this); });
260 }
261
262 void
263 EarlyNameResolver::visit (AST::MatchExpr &expr)
264 {
265 expr.get_scrutinee_expr ().accept_vis (*this);
266
267 scoped (expr.get_node_id (), [&expr, this] () {
268 for (auto &arm : expr.get_match_cases ())
269 {
270 scoped (arm.get_node_id (), [&arm, this] () {
271 if (arm.get_arm ().has_match_arm_guard ())
272 arm.get_arm ().get_guard_expr ().accept_vis (*this);
273
274 for (auto &pattern : arm.get_arm ().get_patterns ())
275 pattern->accept_vis (*this);
276
277 arm.get_expr ().accept_vis (*this);
278 });
279 }
280 });
281 }
282
283 void
284 EarlyNameResolver::visit (AST::LifetimeWhereClauseItem &)
285 {}
286
287 void
288 EarlyNameResolver::visit (AST::Module &module)
289 {
290 if (module.get_kind () == AST::Module::UNLOADED)
291 module.load_items ();
292
293 // so we need to only go "one scope down" for fetching macros. Macros within
294 // functions are still scoped only within that function. But we have to be
295 // careful because nested modules with #[macro_use] actually works!
296 std::vector<std::unique_ptr<AST::Item>> new_items;
297 auto items = module.take_items ();
298
299 scoped (module.get_node_id (), [&items, &new_items, this] {
300 for (auto &&item : items)
301 {
302 auto new_macros = std::vector<std::unique_ptr<AST::Item>> ();
303
304 if (item->get_item_kind () == AST::Item::Kind::Module)
305 new_macros = accumulate_escaped_macros (
306 *static_cast<AST::Module *> (item.get ()));
307
308 new_items.emplace_back (std::move (item));
309 std::move (new_macros.begin (), new_macros.end (),
310 std::back_inserter (new_items));
311 }
312 });
313
314 module.set_items (std::move (new_items));
315
316 scoped (module.get_node_id (), [&module, this] () {
317 for (auto &item : module.get_items ())
318 item->accept_vis (*this);
319 });
320 }
321
322 void
323 EarlyNameResolver::visit (AST::ExternCrate &)
324 {}
325
326 void
327 EarlyNameResolver::visit (AST::UseTreeGlob &)
328 {}
329
330 void
331 EarlyNameResolver::visit (AST::UseTreeList &)
332 {}
333
334 void
335 EarlyNameResolver::visit (AST::UseTreeRebind &)
336 {}
337
338 void
339 EarlyNameResolver::visit (AST::UseDeclaration &)
340 {}
341
342 void
343 EarlyNameResolver::visit (AST::EnumItem &)
344 {}
345
346 void
347 EarlyNameResolver::visit (AST::Union &)
348 {}
349
350 void
351 EarlyNameResolver::visit (AST::TraitItemType &)
352 {}
353
354 void
355 EarlyNameResolver::visit (AST::Trait &trait)
356 {
357 // shouldn't need to visit trait.get_implicit_self ()
358
359 for (auto &generic : trait.get_generic_params ())
360 generic->accept_vis (*this);
361
362 scoped (trait.get_node_id (), [&trait, this] () {
363 for (auto &item : trait.get_trait_items ())
364 item->accept_vis (*this);
365 });
366 }
367
368 void
369 EarlyNameResolver::visit (AST::InherentImpl &impl)
370 {
371 impl.get_type ().accept_vis (*this);
372
373 for (auto &generic : impl.get_generic_params ())
374 generic->accept_vis (*this);
375
376 scoped (impl.get_node_id (), [&impl, this] () {
377 for (auto &item : impl.get_impl_items ())
378 item->accept_vis (*this);
379 });
380 }
381
382 void
383 EarlyNameResolver::visit (AST::TraitImpl &impl)
384 {
385 impl.get_type ().accept_vis (*this);
386
387 for (auto &generic : impl.get_generic_params ())
388 generic->accept_vis (*this);
389
390 scoped (impl.get_node_id (), [&impl, this] () {
391 for (auto &item : impl.get_impl_items ())
392 item->accept_vis (*this);
393 });
394 }
395
396 void
397 EarlyNameResolver::visit (AST::ExternalTypeItem &item)
398 {
399 // nothing to do?
400 }
401
402 void
403 EarlyNameResolver::visit (AST::ExternBlock &block)
404 {
405 scoped (block.get_node_id (), [&block, this] () {
406 for (auto &item : block.get_extern_items ())
407 item->accept_vis (*this);
408 });
409 }
410
411 void
412 EarlyNameResolver::visit (AST::MacroMatchRepetition &)
413 {}
414
415 void
416 EarlyNameResolver::visit (AST::MacroMatcher &)
417 {}
418
419 void
420 EarlyNameResolver::visit (AST::MacroRulesDefinition &rules_def)
421 {
422 auto path = CanonicalPath::new_seg (rules_def.get_node_id (),
423 rules_def.get_rule_name ().as_string ());
424 resolver.get_macro_scope ().insert (path, rules_def.get_node_id (),
425 rules_def.get_locus ());
426
427 /* Since the EarlyNameResolver runs multiple time (fixed point algorithm)
428 * we could be inserting the same macro def over and over again until we
429 * implement some optimizations */
430 // FIXME: ARTHUR: Remove that lookup and add proper optimizations instead
431 if (mappings.lookup_macro_def (rules_def.get_node_id ()))
432 return;
433
434 mappings.insert_macro_def (&rules_def);
435 rust_debug_loc (rules_def.get_locus (), "inserting macro def: [%s]",
436 path.get ().c_str ());
437 }
438
439 void
440 EarlyNameResolver::visit (AST::MacroInvocation &invoc)
441 {
442 auto &invoc_data = invoc.get_invoc_data ();
443 auto has_semicolon = invoc.has_semicolon ();
444
445 if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin)
446 for (auto &pending_invoc : invoc.get_pending_eager_invocations ())
447 pending_invoc->accept_vis (*this);
448
449 // ??
450 // switch on type of macro:
451 // - '!' syntax macro (inner switch)
452 // - procedural macro - "A token-based function-like macro"
453 // - 'macro_rules' (by example/pattern-match) macro? or not? "an
454 // AST-based function-like macro"
455 // - else is unreachable
456 // - attribute syntax macro (inner switch)
457 // - procedural macro attribute syntax - "A token-based attribute
458 // macro"
459 // - legacy macro attribute syntax? - "an AST-based attribute macro"
460 // - non-macro attribute: mark known
461 // - else is unreachable
462 // - derive macro (inner switch)
463 // - derive or legacy derive - "token-based" vs "AST-based"
464 // - else is unreachable
465 // - derive container macro - unreachable
466
467 // lookup the rules for this macro
468 NodeId resolved_node = UNKNOWN_NODEID;
469 NodeId source_node = UNKNOWN_NODEID;
470 if (has_semicolon)
471 source_node = invoc.get_macro_node_id ();
472 else
473 source_node = invoc.get_node_id ();
474 auto seg
475 = CanonicalPath::new_seg (source_node, invoc_data.get_path ().as_string ());
476
477 bool found = resolver.get_macro_scope ().lookup (seg, &resolved_node);
478 if (!found)
479 {
480 rust_error_at (invoc.get_locus (), ErrorCode::E0433,
481 "could not resolve macro invocation %qs",
482 seg.get ().c_str ());
483 return;
484 }
485
486 // lookup the rules
487 auto rules_def = mappings.lookup_macro_def (resolved_node);
488
489 auto &outer_attrs = rules_def.value ()->get_outer_attrs ();
490 bool is_builtin
491 = std::any_of (outer_attrs.begin (), outer_attrs.end (),
492 [] (AST::Attribute attr) {
493 return attr.get_path ()
494 == Values::Attributes::RUSTC_BUILTIN_MACRO;
495 });
496
497 if (is_builtin)
498 {
499 auto builtin_kind = builtin_macro_from_string (
500 rules_def.value ()->get_rule_name ().as_string ());
501 invoc.map_to_builtin (builtin_kind.value ());
502 }
503
504 auto attributes = rules_def.value ()->get_outer_attrs ();
505
506 /* Since the EarlyNameResolver runs multiple time (fixed point algorithm)
507 * we could be inserting the same macro def over and over again until we
508 * implement some optimizations */
509 // FIXME: ARTHUR: Remove that lookup and add proper optimizations instead
510 if (mappings.lookup_macro_invocation (invoc))
511 return;
512
513 mappings.insert_macro_invocation (invoc, *rules_def);
514 }
515
516 // FIXME: ARTHUR: Do we need to resolve these as well here?
517
518 void
519 EarlyNameResolver::visit (AST::MetaItemPath &)
520 {}
521
522 void
523 EarlyNameResolver::visit (AST::MetaItemSeq &)
524 {}
525
526 void
527 EarlyNameResolver::visit (AST::MetaNameValueStr &)
528 {}
529
530 void
531 EarlyNameResolver::visit (AST::MetaListPaths &)
532 {}
533
534 void
535 EarlyNameResolver::visit (AST::MetaListNameValueStr &)
536 {}
537
538 void
539 EarlyNameResolver::visit (AST::RangePatternBoundLiteral &)
540 {}
541
542 void
543 EarlyNameResolver::visit (AST::RangePatternBoundPath &)
544 {}
545
546 void
547 EarlyNameResolver::visit (AST::RangePatternBoundQualPath &)
548 {}
549
550 void
551 EarlyNameResolver::visit (AST::StructPatternFieldIdent &)
552 {}
553
554 void
555 EarlyNameResolver::visit (AST::StructPattern &)
556 {}
557
558 void
559 EarlyNameResolver::visit (AST::TupleStructPattern &pattern)
560 {
561 pattern.get_items ().accept_vis (*this);
562 }
563
564 void
565 EarlyNameResolver::visit (AST::TupleType &)
566 {}
567
568 void
569 EarlyNameResolver::visit (AST::RawPointerType &)
570 {}
571
572 void
573 EarlyNameResolver::visit (AST::ReferenceType &)
574 {}
575
576 void
577 EarlyNameResolver::visit (AST::ArrayType &)
578 {}
579
580 void
581 EarlyNameResolver::visit (AST::SliceType &)
582 {}
583
584 void
585 EarlyNameResolver::visit (AST::InferredType &)
586 {}
587
588 } // namespace Resolver
589 } // namespace Rust