aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/expand/rust-macro-expand.h
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-02-13 11:15:24 +0000
committerGitHub <noreply@github.com>2023-02-13 11:15:24 +0000
commit59d4ee6cc1b14ddc01d062a41bec364e959793c7 (patch)
treedc3137f8905d5ad3cebefb6b766859d49944a9eb /gcc/rust/expand/rust-macro-expand.h
parent3a8c8d0d41b57fbb49ab39715b70495d5d1e8dd1 (diff)
parentf67f5409d2fe4191ab24b5eb634c26306386fb25 (diff)
downloadgcc-59d4ee6cc1b14ddc01d062a41bec364e959793c7.zip
gcc-59d4ee6cc1b14ddc01d062a41bec364e959793c7.tar.gz
gcc-59d4ee6cc1b14ddc01d062a41bec364e959793c7.tar.bz2
Merge #1750
1750: Implement fixed point macro expansion r=CohenArthur a=CohenArthur This is a cleanup of #1606's branch, which also contains the code necessary for performing eager macro expansion in builtin macros. This commit changes our macro expansion system from an eager and recursive macro expansion to a fixed-point like system. Instead of, when seeing a macro invocation, expanding it and all of the macros within it, we now perform multiple passes of expansion on the entire crate. This, however, leads to a problem. Rust macros are expanded lazily, but Rust builtin macros should be expanded eagerly. Due to this, we must work around the lazy expansion in builtin macros and perform eager expansion for each pass of the fixed-point, before finally expanding the builtin when there are no longer any inner macro invocations. To perform proper macro scoping, the ENR now keeps track of the current scope (`current_scope` member) and resolves macros accordingly. This is done through the use of the `scoped` method, which creates a new scope, runs a specified lambda and then exits the scope. This prevents pushing/popping errors that we've seen happen already in similar contexts. We might think about generalizing it to other classes, providing a `Scoped<EntryFn, ExitFn>` class or similar Fixes #1795 Co-authored-by: Arthur Cohen <arthur.cohen@embecosm.com>
Diffstat (limited to 'gcc/rust/expand/rust-macro-expand.h')
-rw-r--r--gcc/rust/expand/rust-macro-expand.h63
1 files changed, 32 insertions, 31 deletions
diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h
index 6253a4e..e440edf 100644
--- a/gcc/rust/expand/rust-macro-expand.h
+++ b/gcc/rust/expand/rust-macro-expand.h
@@ -231,7 +231,7 @@ struct MacroExpander
: cfg (cfg), crate (crate), session (session),
sub_stack (SubstitutionScope ()),
expanded_fragment (AST::Fragment::create_error ()),
- resolver (Resolver::Resolver::get ()),
+ has_changed_flag (false), resolver (Resolver::Resolver::get ()),
mappings (Analysis::Mappings::get ())
{}
@@ -240,6 +240,12 @@ struct MacroExpander
// Expands all macros in the crate passed in.
void expand_crate ();
+ /**
+ * Expand the eager invocations contained within a builtin macro invocation.
+ * Called by `expand_invoc` when expanding builtin invocations.
+ */
+ void expand_eager_invocations (AST::MacroInvocation &invoc);
+
/* Expands a macro invocation - possibly make both
* have similar duck-typed interface and use templates?*/
// should this be public or private?
@@ -315,49 +321,44 @@ struct MacroExpander
void set_expanded_fragment (AST::Fragment &&fragment)
{
+ if (!fragment.is_error ())
+ has_changed_flag = true;
+
expanded_fragment = std::move (fragment);
}
- AST::Fragment take_expanded_fragment (AST::ASTVisitor &vis)
+ AST::Fragment take_expanded_fragment ()
{
- AST::Fragment old_fragment = std::move (expanded_fragment);
- auto accumulator = std::vector<AST::SingleASTNode> ();
+ auto fragment = std::move (expanded_fragment);
expanded_fragment = AST::Fragment::create_error ();
- auto early_name_resolver = Resolver::EarlyNameResolver ();
-
- for (auto &node : old_fragment.get_nodes ())
- {
- expansion_depth++;
-
- node.accept_vis (early_name_resolver);
- node.accept_vis (vis);
- // we'll decide the next move according to the outcome of the macro
- // expansion
- if (expanded_fragment.is_error ())
- accumulator.push_back (node); // if expansion fails, there might be a
- // non-macro expression we need to keep
- else
- {
- // if expansion succeeded, then we need to merge the fragment with
- // the contents in the accumulator, so that our final expansion
- // result will contain non-macro nodes as it should
- auto new_nodes = expanded_fragment.get_nodes ();
- std::move (new_nodes.begin (), new_nodes.end (),
- std::back_inserter (accumulator));
- expanded_fragment = AST::Fragment::complete (accumulator);
- }
- expansion_depth--;
- }
-
- return old_fragment;
+
+ return fragment;
}
+ /**
+ * Has the MacroExpander expanded a macro since its state was last reset?
+ */
+ bool has_changed () const { return has_changed_flag; }
+
+ /**
+ * Reset the expander's "changed" state. This function should be executed at
+ * each iteration in a fixed point loop
+ */
+ void reset_changed_state () { has_changed_flag = false; }
+
+ AST::MacroRulesDefinition *get_last_definition () { return last_def; }
+ AST::MacroInvocation *get_last_invocation () { return last_invoc; }
+
private:
AST::Crate &crate;
Session &session;
SubstitutionScope sub_stack;
std::vector<ContextType> context;
AST::Fragment expanded_fragment;
+ bool has_changed_flag;
+
+ AST::MacroRulesDefinition *last_def;
+ AST::MacroInvocation *last_invoc;
public:
Resolver::Resolver *resolver;