+++ /dev/null
-// Copyright (C) 2020-2025 Free Software Foundation, Inc.
-
-// This file is part of GCC.
-
-// GCC is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3, or (at your option) any later
-// version.
-
-// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-// WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with GCC; see the file COPYING3. If not see
-// <http://www.gnu.org/licenses/>.
-
-#include "rust-early-name-resolver.h"
-#include "rust-pattern.h"
-#include "rust-name-resolver.h"
-#include "rust-macro-builtins.h"
-#include "rust-attribute-values.h"
-
-namespace Rust {
-namespace Resolver {
-
-// Check if a module contains the `#[macro_use]` attribute
-static bool
-is_macro_use_module (const AST::Module &mod)
-{
- for (const auto &attr : mod.get_outer_attrs ())
- if (attr.get_path ().as_string () == Values::Attributes::MACRO_USE)
- return true;
-
- return false;
-}
-
-std::vector<std::unique_ptr<AST::Item>>
-EarlyNameResolver::accumulate_escaped_macros (AST::Module &module)
-{
- if (!is_macro_use_module (module))
- return {};
-
- // Parse the module's items if they haven't been expanded and the file
- // should be parsed (i.e isn't hidden behind an untrue or impossible cfg
- // directive)
- if (module.get_kind () == AST::Module::UNLOADED)
- module.load_items ();
-
- std::vector<std::unique_ptr<AST::Item>> escaped_macros;
-
- scoped (module.get_node_id (), [&module, &escaped_macros, this] {
- for (auto &item : module.get_items ())
- {
- if (item->get_item_kind () == AST::Item::Kind::Module)
- {
- auto &module = *static_cast<AST::Module *> (item.get ());
- auto new_macros = accumulate_escaped_macros (module);
-
- std::move (new_macros.begin (), new_macros.end (),
- std::back_inserter (escaped_macros));
-
- continue;
- }
-
- if (item->get_item_kind () == AST::Item::Kind::MacroRulesDefinition)
- escaped_macros.emplace_back (item->clone_item ());
- }
- });
-
- return escaped_macros;
-}
-
-EarlyNameResolver::EarlyNameResolver ()
- : current_scope (UNKNOWN_NODEID), resolver (*Resolver::get ()),
- mappings (Analysis::Mappings::get ())
-{}
-
-void
-EarlyNameResolver::go (AST::Crate &crate)
-{
- visit (crate);
-}
-
-void
-EarlyNameResolver::resolve_generic_args (AST::GenericArgs &generic_args)
-{
- for (auto &arg : generic_args.get_generic_args ())
- arg.accept_vis (*this);
-
- for (auto &arg : generic_args.get_binding_args ())
- arg.get_type ().accept_vis (*this);
-}
-
-void
-EarlyNameResolver::resolve_qualified_path_type (AST::QualifiedPathType &path)
-{
- path.get_type ().accept_vis (*this);
-
- if (path.has_as_clause ())
- path.get_as_type_path ().accept_vis (*this);
-}
-
-void
-EarlyNameResolver::visit (AST::Crate &crate)
-{
- std::vector<std::unique_ptr<AST::Item>> new_items;
- auto items = crate.take_items ();
-
- scoped (crate.get_node_id (), [&items, &new_items, this] {
- for (auto &&item : items)
- {
- auto new_macros = std::vector<std::unique_ptr<AST::Item>> ();
-
- if (item->get_item_kind () == AST::Item::Kind::Module)
- new_macros = accumulate_escaped_macros (
- *static_cast<AST::Module *> (item.get ()));
-
- new_items.emplace_back (std::move (item));
- std::move (new_macros.begin (), new_macros.end (),
- std::back_inserter (new_items));
- }
- });
-
- crate.set_items (std::move (new_items));
-
- scoped (crate.get_node_id (), [&crate, this] () {
- for (auto &item : crate.items)
- item->accept_vis (*this);
- });
-}
-
-void
-EarlyNameResolver::visit (AST::DelimTokenTree &)
-{}
-
-void
-EarlyNameResolver::visit (AST::AttrInputMetaItemContainer &)
-{}
-
-void
-EarlyNameResolver::visit (AST::IdentifierExpr &)
-{}
-
-void
-EarlyNameResolver::visit (AST::LifetimeParam &)
-{}
-
-void
-EarlyNameResolver::visit (AST::ConstGenericParam &)
-{}
-
-// FIXME: ARTHUR: Do we need to perform macro resolution for paths as well?
-// std::arch::asm!()?
-void
-EarlyNameResolver::visit (AST::PathInExpression &path)
-{
- if (!path.is_lang_item ())
- for (auto &segment : path.get_segments ())
- if (segment.has_generic_args ())
- resolve_generic_args (segment.get_generic_args ());
-}
-
-void
-EarlyNameResolver::visit (AST::TypePathSegmentGeneric &segment)
-{
- if (segment.has_generic_args ())
- resolve_generic_args (segment.get_generic_args ());
-}
-
-void
-EarlyNameResolver::visit (AST::QualifiedPathInExpression &path)
-{
- resolve_qualified_path_type (path.get_qualified_path_type ());
-
- for (auto &segment : path.get_segments ())
- if (segment.has_generic_args ())
- resolve_generic_args (segment.get_generic_args ());
-}
-
-void
-EarlyNameResolver::visit (AST::QualifiedPathInType &path)
-{
- resolve_qualified_path_type (path.get_qualified_path_type ());
-
- for (auto &segment : path.get_segments ())
- segment->accept_vis (*this);
-}
-
-void
-EarlyNameResolver::visit (AST::LiteralExpr &)
-{}
-
-void
-EarlyNameResolver::visit (AST::AttrInputLiteral &)
-{}
-
-void
-EarlyNameResolver::visit (AST::AttrInputMacro &)
-{}
-
-void
-EarlyNameResolver::visit (AST::MetaItemLitExpr &)
-{}
-
-void
-EarlyNameResolver::visit (AST::MetaItemPathExpr &)
-{}
-
-void
-EarlyNameResolver::visit (AST::StructExprStruct &)
-{}
-
-void
-EarlyNameResolver::visit (AST::StructExprFieldIdentifier &)
-{}
-
-void
-EarlyNameResolver::visit (AST::StructExprStructBase &)
-{}
-
-void
-EarlyNameResolver::visit (AST::BlockExpr &expr)
-{
- scoped (expr.get_node_id (), [&expr, this] () {
- for (auto &stmt : expr.get_statements ())
- stmt->accept_vis (*this);
-
- if (expr.has_tail_expr ())
- expr.get_tail_expr ().accept_vis (*this);
- });
-}
-
-void
-EarlyNameResolver::visit (AST::ContinueExpr &)
-{}
-
-void
-EarlyNameResolver::visit (AST::RangeFullExpr &)
-{}
-
-void
-EarlyNameResolver::visit (AST::ForLoopExpr &expr)
-{
- scoped (expr.get_node_id (), [&expr, this] () {
- expr.get_pattern ().accept_vis (*this);
- expr.get_iterator_expr ().accept_vis (*this);
- expr.get_loop_block ().accept_vis (*this);
- });
-}
-
-void
-EarlyNameResolver::visit (AST::IfLetExpr &expr)
-{
- expr.get_value_expr ().accept_vis (*this);
-
- scoped (expr.get_node_id (),
- [&expr, this] () { expr.get_if_block ().accept_vis (*this); });
-}
-
-void
-EarlyNameResolver::visit (AST::MatchExpr &expr)
-{
- expr.get_scrutinee_expr ().accept_vis (*this);
-
- scoped (expr.get_node_id (), [&expr, this] () {
- for (auto &arm : expr.get_match_cases ())
- {
- scoped (arm.get_node_id (), [&arm, this] () {
- if (arm.get_arm ().has_match_arm_guard ())
- arm.get_arm ().get_guard_expr ().accept_vis (*this);
-
- for (auto &pattern : arm.get_arm ().get_patterns ())
- pattern->accept_vis (*this);
-
- arm.get_expr ().accept_vis (*this);
- });
- }
- });
-}
-
-void
-EarlyNameResolver::visit (AST::LifetimeWhereClauseItem &)
-{}
-
-void
-EarlyNameResolver::visit (AST::Module &module)
-{
- if (module.get_kind () == AST::Module::UNLOADED)
- module.load_items ();
-
- // so we need to only go "one scope down" for fetching macros. Macros within
- // functions are still scoped only within that function. But we have to be
- // careful because nested modules with #[macro_use] actually works!
- std::vector<std::unique_ptr<AST::Item>> new_items;
- auto items = module.take_items ();
-
- scoped (module.get_node_id (), [&items, &new_items, this] {
- for (auto &&item : items)
- {
- auto new_macros = std::vector<std::unique_ptr<AST::Item>> ();
-
- if (item->get_item_kind () == AST::Item::Kind::Module)
- new_macros = accumulate_escaped_macros (
- *static_cast<AST::Module *> (item.get ()));
-
- new_items.emplace_back (std::move (item));
- std::move (new_macros.begin (), new_macros.end (),
- std::back_inserter (new_items));
- }
- });
-
- module.set_items (std::move (new_items));
-
- scoped (module.get_node_id (), [&module, this] () {
- for (auto &item : module.get_items ())
- item->accept_vis (*this);
- });
-}
-
-void
-EarlyNameResolver::visit (AST::ExternCrate &)
-{}
-
-void
-EarlyNameResolver::visit (AST::UseTreeGlob &)
-{}
-
-void
-EarlyNameResolver::visit (AST::UseTreeList &)
-{}
-
-void
-EarlyNameResolver::visit (AST::UseTreeRebind &)
-{}
-
-void
-EarlyNameResolver::visit (AST::UseDeclaration &)
-{}
-
-void
-EarlyNameResolver::visit (AST::EnumItem &)
-{}
-
-void
-EarlyNameResolver::visit (AST::Union &)
-{}
-
-void
-EarlyNameResolver::visit (AST::TraitItemType &)
-{}
-
-void
-EarlyNameResolver::visit (AST::Trait &trait)
-{
- // shouldn't need to visit trait.get_implicit_self ()
-
- for (auto &generic : trait.get_generic_params ())
- generic->accept_vis (*this);
-
- scoped (trait.get_node_id (), [&trait, this] () {
- for (auto &item : trait.get_trait_items ())
- item->accept_vis (*this);
- });
-}
-
-void
-EarlyNameResolver::visit (AST::InherentImpl &impl)
-{
- impl.get_type ().accept_vis (*this);
-
- for (auto &generic : impl.get_generic_params ())
- generic->accept_vis (*this);
-
- scoped (impl.get_node_id (), [&impl, this] () {
- for (auto &item : impl.get_impl_items ())
- item->accept_vis (*this);
- });
-}
-
-void
-EarlyNameResolver::visit (AST::TraitImpl &impl)
-{
- impl.get_type ().accept_vis (*this);
-
- for (auto &generic : impl.get_generic_params ())
- generic->accept_vis (*this);
-
- scoped (impl.get_node_id (), [&impl, this] () {
- for (auto &item : impl.get_impl_items ())
- item->accept_vis (*this);
- });
-}
-
-void
-EarlyNameResolver::visit (AST::ExternalTypeItem &item)
-{
- // nothing to do?
-}
-
-void
-EarlyNameResolver::visit (AST::ExternBlock &block)
-{
- scoped (block.get_node_id (), [&block, this] () {
- for (auto &item : block.get_extern_items ())
- item->accept_vis (*this);
- });
-}
-
-void
-EarlyNameResolver::visit (AST::MacroMatchRepetition &)
-{}
-
-void
-EarlyNameResolver::visit (AST::MacroMatcher &)
-{}
-
-void
-EarlyNameResolver::visit (AST::MacroRulesDefinition &rules_def)
-{
- auto path = CanonicalPath::new_seg (rules_def.get_node_id (),
- rules_def.get_rule_name ().as_string ());
- resolver.get_macro_scope ().insert (path, rules_def.get_node_id (),
- rules_def.get_locus ());
-
- /* Since the EarlyNameResolver runs multiple time (fixed point algorithm)
- * we could be inserting the same macro def over and over again until we
- * implement some optimizations */
- // FIXME: ARTHUR: Remove that lookup and add proper optimizations instead
- if (mappings.lookup_macro_def (rules_def.get_node_id ()))
- return;
-
- mappings.insert_macro_def (&rules_def);
- rust_debug_loc (rules_def.get_locus (), "inserting macro def: [%s]",
- path.get ().c_str ());
-}
-
-void
-EarlyNameResolver::visit (AST::MacroInvocation &invoc)
-{
- auto &invoc_data = invoc.get_invoc_data ();
- auto has_semicolon = invoc.has_semicolon ();
-
- if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin)
- for (auto &pending_invoc : invoc.get_pending_eager_invocations ())
- pending_invoc->accept_vis (*this);
-
- // ??
- // switch on type of macro:
- // - '!' syntax macro (inner switch)
- // - procedural macro - "A token-based function-like macro"
- // - 'macro_rules' (by example/pattern-match) macro? or not? "an
- // AST-based function-like macro"
- // - else is unreachable
- // - attribute syntax macro (inner switch)
- // - procedural macro attribute syntax - "A token-based attribute
- // macro"
- // - legacy macro attribute syntax? - "an AST-based attribute macro"
- // - non-macro attribute: mark known
- // - else is unreachable
- // - derive macro (inner switch)
- // - derive or legacy derive - "token-based" vs "AST-based"
- // - else is unreachable
- // - derive container macro - unreachable
-
- // lookup the rules for this macro
- NodeId resolved_node = UNKNOWN_NODEID;
- NodeId source_node = UNKNOWN_NODEID;
- if (has_semicolon)
- source_node = invoc.get_macro_node_id ();
- else
- source_node = invoc.get_node_id ();
- auto seg
- = CanonicalPath::new_seg (source_node, invoc_data.get_path ().as_string ());
-
- bool found = resolver.get_macro_scope ().lookup (seg, &resolved_node);
- if (!found)
- {
- rust_error_at (invoc.get_locus (), ErrorCode::E0433,
- "could not resolve macro invocation %qs",
- seg.get ().c_str ());
- return;
- }
-
- // lookup the rules
- auto rules_def = mappings.lookup_macro_def (resolved_node);
-
- auto &outer_attrs = rules_def.value ()->get_outer_attrs ();
- bool is_builtin
- = std::any_of (outer_attrs.begin (), outer_attrs.end (),
- [] (AST::Attribute attr) {
- return attr.get_path ()
- == Values::Attributes::RUSTC_BUILTIN_MACRO;
- });
-
- if (is_builtin)
- {
- auto builtin_kind = builtin_macro_from_string (
- rules_def.value ()->get_rule_name ().as_string ());
- invoc.map_to_builtin (builtin_kind.value ());
- }
-
- auto attributes = rules_def.value ()->get_outer_attrs ();
-
- /* Since the EarlyNameResolver runs multiple time (fixed point algorithm)
- * we could be inserting the same macro def over and over again until we
- * implement some optimizations */
- // FIXME: ARTHUR: Remove that lookup and add proper optimizations instead
- if (mappings.lookup_macro_invocation (invoc))
- return;
-
- mappings.insert_macro_invocation (invoc, *rules_def);
-}
-
-// FIXME: ARTHUR: Do we need to resolve these as well here?
-
-void
-EarlyNameResolver::visit (AST::MetaItemPath &)
-{}
-
-void
-EarlyNameResolver::visit (AST::MetaItemSeq &)
-{}
-
-void
-EarlyNameResolver::visit (AST::MetaNameValueStr &)
-{}
-
-void
-EarlyNameResolver::visit (AST::MetaListPaths &)
-{}
-
-void
-EarlyNameResolver::visit (AST::MetaListNameValueStr &)
-{}
-
-void
-EarlyNameResolver::visit (AST::RangePatternBoundLiteral &)
-{}
-
-void
-EarlyNameResolver::visit (AST::RangePatternBoundPath &)
-{}
-
-void
-EarlyNameResolver::visit (AST::RangePatternBoundQualPath &)
-{}
-
-void
-EarlyNameResolver::visit (AST::StructPatternFieldIdent &)
-{}
-
-void
-EarlyNameResolver::visit (AST::StructPattern &)
-{}
-
-void
-EarlyNameResolver::visit (AST::TupleStructPattern &pattern)
-{
- pattern.get_items ().accept_vis (*this);
-}
-
-void
-EarlyNameResolver::visit (AST::TupleType &)
-{}
-
-void
-EarlyNameResolver::visit (AST::RawPointerType &)
-{}
-
-void
-EarlyNameResolver::visit (AST::ReferenceType &)
-{}
-
-void
-EarlyNameResolver::visit (AST::ArrayType &)
-{}
-
-void
-EarlyNameResolver::visit (AST::SliceType &)
-{}
-
-void
-EarlyNameResolver::visit (AST::InferredType &)
-{}
-
-} // namespace Resolver
-} // namespace Rust
+++ /dev/null
-// Copyright (C) 2020-2025 Free Software Foundation, Inc.
-
-// This file is part of GCC.
-
-// GCC is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3, or (at your option) any later
-// version.
-
-// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-// WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with GCC; see the file COPYING3. If not see
-// <http://www.gnu.org/licenses/>.
-
-#ifndef RUST_EARLY_NAME_RESOLVER_H
-#define RUST_EARLY_NAME_RESOLVER_H
-
-#include "rust-name-resolver.h"
-#include "rust-system.h"
-#include "rust-ast.h"
-#include "rust-ast-visitor.h"
-
-namespace Rust {
-namespace Resolver {
-
-class EarlyNameResolver : public AST::DefaultASTVisitor
-{
-public:
- EarlyNameResolver ();
-
- void go (AST::Crate &crate);
-
-private:
- using AST::DefaultASTVisitor::visit;
-
- /**
- * Execute a lambda within a scope. This is equivalent to calling
- * `enter_scope` before your code and `exit_scope` after. This ensures
- * no errors can be committed
- */
- void scoped (NodeId scope_id, std::function<void ()> fn)
- {
- auto old_scope = current_scope;
- current_scope = scope_id;
- resolver.get_macro_scope ().push (scope_id);
- resolver.push_new_macro_rib (resolver.get_macro_scope ().peek ());
-
- fn ();
-
- resolver.get_macro_scope ().pop ();
- current_scope = old_scope;
- }
-
- /**
- * Accumulate all of the nested macros which escape their module through the
- * use of the #[macro_use] attribute.
- *
- * This function recursively accumulates macros in all of the nested modules
- * of an item container (an AST::Crate or an AST::Module) and returns this new
- * list of items. You can then use the `take_items` and `set_items` functions
- * on these containers to replace their list of items.
- */
- std::vector<std::unique_ptr<AST::Item>>
- accumulate_escaped_macros (AST::Module &module);
-
- /**
- * The "scope" we are currently in.
- *
- * This involves lexical scopes:
- *
- * ```rust
- * // current_scope = crate_id;
- * macro_rules! foo { () => {} )
- *
- * {
- * // current_scope = current_block_id;
- * macro_rules! foo { () => { something!(); } }
- * }
- * // current_scope = crate_id;
- * ```
- *
- * as well as any sort of scope-like structure that might impact import name
- * resolution or macro name resolution:
- *
- * ```rust
- * macro_rules! foo {
- * () => { fn empty() {} }
- * }
- *
- *
- * trait Foo {
- * fn foo() {
- * fn inner_foo() {
- * macro_rules! foo { () => {} )
- *
- * foo!();
- * }
- *
- * foo!();
- * }
- *
- * foo!();
- * }
- *
- * foo!();
- * ```
- */
- NodeId current_scope;
-
- /* The crate's scope */
- NodeId crate_scope;
-
- Resolver &resolver;
- Analysis::Mappings &mappings;
-
- /**
- * Early name-resolve generic args, which can be macro invocations
- */
- void resolve_generic_args (AST::GenericArgs &generic_args);
-
- /**
- * Early name-resolve a qualified path type, which can contain macro
- * invocations
- */
- void resolve_qualified_path_type (AST::QualifiedPathType &path);
-
- virtual void visit (AST::Crate &crate);
- virtual void visit (AST::DelimTokenTree &delim_tok_tree);
- virtual void visit (AST::AttrInputMetaItemContainer &input);
- virtual void visit (AST::IdentifierExpr &ident_expr);
- virtual void visit (AST::LifetimeParam &lifetime_param);
- virtual void visit (AST::ConstGenericParam &const_param);
- virtual void visit (AST::PathInExpression &path);
- virtual void visit (AST::TypePathSegmentGeneric &segment);
- virtual void visit (AST::QualifiedPathInExpression &path);
- virtual void visit (AST::QualifiedPathInType &path);
- virtual void visit (AST::LiteralExpr &expr);
- virtual void visit (AST::AttrInputLiteral &attr_input);
- virtual void visit (AST::AttrInputMacro &attr_input);
- virtual void visit (AST::MetaItemLitExpr &meta_item);
- virtual void visit (AST::MetaItemPathExpr &meta_item);
- virtual void visit (AST::StructExprStruct &expr);
- virtual void visit (AST::StructExprFieldIdentifier &field);
- virtual void visit (AST::StructExprStructBase &expr);
- virtual void visit (AST::BlockExpr &expr);
- virtual void visit (AST::ContinueExpr &expr);
- virtual void visit (AST::RangeFullExpr &expr);
- virtual void visit (AST::ForLoopExpr &expr);
- virtual void visit (AST::IfLetExpr &expr);
- virtual void visit (AST::MatchExpr &expr);
- virtual void visit (AST::LifetimeWhereClauseItem &item);
- virtual void visit (AST::Module &module);
- virtual void visit (AST::ExternCrate &crate);
- virtual void visit (AST::UseTreeGlob &use_tree);
- virtual void visit (AST::UseTreeList &use_tree);
- virtual void visit (AST::UseTreeRebind &use_tree);
- virtual void visit (AST::UseDeclaration &use_decl);
- virtual void visit (AST::EnumItem &item);
- virtual void visit (AST::Union &union_item);
- virtual void visit (AST::TraitItemType &item);
- virtual void visit (AST::Trait &trait);
- virtual void visit (AST::InherentImpl &impl);
- virtual void visit (AST::TraitImpl &impl);
- virtual void visit (AST::ExternalTypeItem &item);
- virtual void visit (AST::ExternBlock &block);
- virtual void visit (AST::MacroMatchRepetition &match);
- virtual void visit (AST::MacroMatcher &matcher);
- virtual void visit (AST::MacroRulesDefinition &rules_def);
- virtual void visit (AST::MacroInvocation ¯o_invoc);
- virtual void visit (AST::MetaItemPath &meta_item);
- virtual void visit (AST::MetaItemSeq &meta_item);
- virtual void visit (AST::MetaNameValueStr &meta_item);
- virtual void visit (AST::MetaListPaths &meta_item);
- virtual void visit (AST::MetaListNameValueStr &meta_item);
- virtual void visit (AST::RangePatternBoundLiteral &bound);
- virtual void visit (AST::RangePatternBoundPath &bound);
- virtual void visit (AST::RangePatternBoundQualPath &bound);
- virtual void visit (AST::StructPatternFieldIdent &field);
- virtual void visit (AST::StructPattern &pattern);
- virtual void visit (AST::TupleStructPattern &pattern);
- virtual void visit (AST::TupleType &type);
- virtual void visit (AST::RawPointerType &type);
- virtual void visit (AST::ReferenceType &type);
- virtual void visit (AST::ArrayType &type);
- virtual void visit (AST::SliceType &type);
- virtual void visit (AST::InferredType &type);
-};
-
-} // namespace Resolver
-} // namespace Rust
-
-#endif // RUST_EARLY_NAME_RESOLVER_H