1 // Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 // This file is part of GCC.
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
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
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/>.
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"
28 // Check if a module contains the `#[macro_use]` attribute
30 is_macro_use_module (const AST::Module
&mod
)
32 for (const auto &attr
: mod
.get_outer_attrs ())
33 if (attr
.get_path ().as_string () == Values::Attributes::MACRO_USE
)
39 std::vector
<std::unique_ptr
<AST::Item
>>
40 EarlyNameResolver::accumulate_escaped_macros (AST::Module
&module
)
42 if (!is_macro_use_module (module
))
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
48 if (module
.get_kind () == AST::Module::UNLOADED
)
51 std::vector
<std::unique_ptr
<AST::Item
>> escaped_macros
;
53 scoped (module
.get_node_id (), [&module
, &escaped_macros
, this] {
54 for (auto &item
: module
.get_items ())
56 if (item
->get_item_kind () == AST::Item::Kind::Module
)
58 auto &module
= *static_cast<AST::Module
*> (item
.get ());
59 auto new_macros
= accumulate_escaped_macros (module
);
61 std::move (new_macros
.begin (), new_macros
.end (),
62 std::back_inserter (escaped_macros
));
67 if (item
->get_item_kind () == AST::Item::Kind::MacroRulesDefinition
)
68 escaped_macros
.emplace_back (item
->clone_item ());
72 return escaped_macros
;
75 EarlyNameResolver::EarlyNameResolver ()
76 : current_scope (UNKNOWN_NODEID
), resolver (*Resolver::get ()),
77 mappings (Analysis::Mappings::get ())
81 EarlyNameResolver::go (AST::Crate
&crate
)
87 EarlyNameResolver::resolve_generic_args (AST::GenericArgs
&generic_args
)
89 for (auto &arg
: generic_args
.get_generic_args ())
90 arg
.accept_vis (*this);
92 for (auto &arg
: generic_args
.get_binding_args ())
93 arg
.get_type ().accept_vis (*this);
97 EarlyNameResolver::resolve_qualified_path_type (AST::QualifiedPathType
&path
)
99 path
.get_type ().accept_vis (*this);
101 if (path
.has_as_clause ())
102 path
.get_as_type_path ().accept_vis (*this);
106 EarlyNameResolver::visit (AST::Crate
&crate
)
108 std::vector
<std::unique_ptr
<AST::Item
>> new_items
;
109 auto items
= crate
.take_items ();
111 scoped (crate
.get_node_id (), [&items
, &new_items
, this] {
112 for (auto &&item
: items
)
114 auto new_macros
= std::vector
<std::unique_ptr
<AST::Item
>> ();
116 if (item
->get_item_kind () == AST::Item::Kind::Module
)
117 new_macros
= accumulate_escaped_macros (
118 *static_cast<AST::Module
*> (item
.get ()));
120 new_items
.emplace_back (std::move (item
));
121 std::move (new_macros
.begin (), new_macros
.end (),
122 std::back_inserter (new_items
));
126 crate
.set_items (std::move (new_items
));
128 scoped (crate
.get_node_id (), [&crate
, this] () {
129 for (auto &item
: crate
.items
)
130 item
->accept_vis (*this);
135 EarlyNameResolver::visit (AST::DelimTokenTree
&)
139 EarlyNameResolver::visit (AST::AttrInputMetaItemContainer
&)
143 EarlyNameResolver::visit (AST::IdentifierExpr
&)
147 EarlyNameResolver::visit (AST::LifetimeParam
&)
151 EarlyNameResolver::visit (AST::ConstGenericParam
&)
154 // FIXME: ARTHUR: Do we need to perform macro resolution for paths as well?
155 // std::arch::asm!()?
157 EarlyNameResolver::visit (AST::PathInExpression
&path
)
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 ());
166 EarlyNameResolver::visit (AST::TypePathSegmentGeneric
&segment
)
168 if (segment
.has_generic_args ())
169 resolve_generic_args (segment
.get_generic_args ());
173 EarlyNameResolver::visit (AST::QualifiedPathInExpression
&path
)
175 resolve_qualified_path_type (path
.get_qualified_path_type ());
177 for (auto &segment
: path
.get_segments ())
178 if (segment
.has_generic_args ())
179 resolve_generic_args (segment
.get_generic_args ());
183 EarlyNameResolver::visit (AST::QualifiedPathInType
&path
)
185 resolve_qualified_path_type (path
.get_qualified_path_type ());
187 for (auto &segment
: path
.get_segments ())
188 segment
->accept_vis (*this);
192 EarlyNameResolver::visit (AST::LiteralExpr
&)
196 EarlyNameResolver::visit (AST::AttrInputLiteral
&)
200 EarlyNameResolver::visit (AST::AttrInputMacro
&)
204 EarlyNameResolver::visit (AST::MetaItemLitExpr
&)
208 EarlyNameResolver::visit (AST::MetaItemPathLit
&)
212 EarlyNameResolver::visit (AST::StructExprStruct
&)
216 EarlyNameResolver::visit (AST::StructExprFieldIdentifier
&)
220 EarlyNameResolver::visit (AST::StructExprStructBase
&)
224 EarlyNameResolver::visit (AST::BlockExpr
&expr
)
226 scoped (expr
.get_node_id (), [&expr
, this] () {
227 for (auto &stmt
: expr
.get_statements ())
228 stmt
->accept_vis (*this);
230 if (expr
.has_tail_expr ())
231 expr
.get_tail_expr ().accept_vis (*this);
236 EarlyNameResolver::visit (AST::ContinueExpr
&)
240 EarlyNameResolver::visit (AST::RangeFullExpr
&)
244 EarlyNameResolver::visit (AST::ForLoopExpr
&expr
)
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);
254 EarlyNameResolver::visit (AST::IfLetExpr
&expr
)
256 expr
.get_value_expr ().accept_vis (*this);
258 scoped (expr
.get_node_id (),
259 [&expr
, this] () { expr
.get_if_block ().accept_vis (*this); });
263 EarlyNameResolver::visit (AST::MatchExpr
&expr
)
265 expr
.get_scrutinee_expr ().accept_vis (*this);
267 scoped (expr
.get_node_id (), [&expr
, this] () {
268 for (auto &arm
: expr
.get_match_cases ())
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);
274 for (auto &pattern
: arm
.get_arm ().get_patterns ())
275 pattern
->accept_vis (*this);
277 arm
.get_expr ().accept_vis (*this);
284 EarlyNameResolver::visit (AST::LifetimeWhereClauseItem
&)
288 EarlyNameResolver::visit (AST::Module
&module
)
290 if (module
.get_kind () == AST::Module::UNLOADED
)
291 module
.load_items ();
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 ();
299 scoped (module
.get_node_id (), [&items
, &new_items
, this] {
300 for (auto &&item
: items
)
302 auto new_macros
= std::vector
<std::unique_ptr
<AST::Item
>> ();
304 if (item
->get_item_kind () == AST::Item::Kind::Module
)
305 new_macros
= accumulate_escaped_macros (
306 *static_cast<AST::Module
*> (item
.get ()));
308 new_items
.emplace_back (std::move (item
));
309 std::move (new_macros
.begin (), new_macros
.end (),
310 std::back_inserter (new_items
));
314 module
.set_items (std::move (new_items
));
316 scoped (module
.get_node_id (), [&module
, this] () {
317 for (auto &item
: module
.get_items ())
318 item
->accept_vis (*this);
323 EarlyNameResolver::visit (AST::ExternCrate
&)
327 EarlyNameResolver::visit (AST::UseTreeGlob
&)
331 EarlyNameResolver::visit (AST::UseTreeList
&)
335 EarlyNameResolver::visit (AST::UseTreeRebind
&)
339 EarlyNameResolver::visit (AST::UseDeclaration
&)
343 EarlyNameResolver::visit (AST::EnumItem
&)
347 EarlyNameResolver::visit (AST::Union
&)
351 EarlyNameResolver::visit (AST::TraitItemType
&)
355 EarlyNameResolver::visit (AST::Trait
&trait
)
357 // shouldn't need to visit trait.get_implicit_self ()
359 for (auto &generic
: trait
.get_generic_params ())
360 generic
->accept_vis (*this);
362 scoped (trait
.get_node_id (), [&trait
, this] () {
363 for (auto &item
: trait
.get_trait_items ())
364 item
->accept_vis (*this);
369 EarlyNameResolver::visit (AST::InherentImpl
&impl
)
371 impl
.get_type ().accept_vis (*this);
373 for (auto &generic
: impl
.get_generic_params ())
374 generic
->accept_vis (*this);
376 scoped (impl
.get_node_id (), [&impl
, this] () {
377 for (auto &item
: impl
.get_impl_items ())
378 item
->accept_vis (*this);
383 EarlyNameResolver::visit (AST::TraitImpl
&impl
)
385 impl
.get_type ().accept_vis (*this);
387 for (auto &generic
: impl
.get_generic_params ())
388 generic
->accept_vis (*this);
390 scoped (impl
.get_node_id (), [&impl
, this] () {
391 for (auto &item
: impl
.get_impl_items ())
392 item
->accept_vis (*this);
397 EarlyNameResolver::visit (AST::ExternalTypeItem
&item
)
403 EarlyNameResolver::visit (AST::ExternBlock
&block
)
405 scoped (block
.get_node_id (), [&block
, this] () {
406 for (auto &item
: block
.get_extern_items ())
407 item
->accept_vis (*this);
412 EarlyNameResolver::visit (AST::MacroMatchRepetition
&)
416 EarlyNameResolver::visit (AST::MacroMatcher
&)
420 EarlyNameResolver::visit (AST::MacroRulesDefinition
&rules_def
)
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 ());
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 ()))
434 mappings
.insert_macro_def (&rules_def
);
435 rust_debug_loc (rules_def
.get_locus (), "inserting macro def: [%s]",
436 path
.get ().c_str ());
440 EarlyNameResolver::visit (AST::MacroInvocation
&invoc
)
442 auto &invoc_data
= invoc
.get_invoc_data ();
443 auto has_semicolon
= invoc
.has_semicolon ();
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);
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
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
467 // lookup the rules for this macro
468 NodeId resolved_node
= UNKNOWN_NODEID
;
469 NodeId source_node
= UNKNOWN_NODEID
;
471 source_node
= invoc
.get_macro_node_id ();
473 source_node
= invoc
.get_node_id ();
475 = CanonicalPath::new_seg (source_node
, invoc_data
.get_path ().as_string ());
477 bool found
= resolver
.get_macro_scope ().lookup (seg
, &resolved_node
);
480 rust_error_at (invoc
.get_locus (), ErrorCode::E0433
,
481 "could not resolve macro invocation %qs",
482 seg
.get ().c_str ());
487 auto rules_def
= mappings
.lookup_macro_def (resolved_node
);
489 auto &outer_attrs
= rules_def
.value ()->get_outer_attrs ();
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
;
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 ());
504 auto attributes
= rules_def
.value ()->get_outer_attrs ();
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
))
513 mappings
.insert_macro_invocation (invoc
, *rules_def
);
516 // FIXME: ARTHUR: Do we need to resolve these as well here?
519 EarlyNameResolver::visit (AST::MetaItemPath
&)
523 EarlyNameResolver::visit (AST::MetaItemSeq
&)
527 EarlyNameResolver::visit (AST::MetaNameValueStr
&)
531 EarlyNameResolver::visit (AST::MetaListPaths
&)
535 EarlyNameResolver::visit (AST::MetaListNameValueStr
&)
539 EarlyNameResolver::visit (AST::RangePatternBoundLiteral
&)
543 EarlyNameResolver::visit (AST::RangePatternBoundPath
&)
547 EarlyNameResolver::visit (AST::RangePatternBoundQualPath
&)
551 EarlyNameResolver::visit (AST::StructPatternFieldIdent
&)
555 EarlyNameResolver::visit (AST::StructPattern
&)
559 EarlyNameResolver::visit (AST::TupleStructPattern
&pattern
)
561 pattern
.get_items ().accept_vis (*this);
565 EarlyNameResolver::visit (AST::TupleType
&)
569 EarlyNameResolver::visit (AST::RawPointerType
&)
573 EarlyNameResolver::visit (AST::ReferenceType
&)
577 EarlyNameResolver::visit (AST::ArrayType
&)
581 EarlyNameResolver::visit (AST::SliceType
&)
585 EarlyNameResolver::visit (AST::InferredType
&)
588 } // namespace Resolver