]>
Commit | Line | Data |
---|---|---|
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 |