aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-02-17 17:02:43 +0000
committerGitHub <noreply@github.com>2022-02-17 17:02:43 +0000
commit9fb06d66cef70584e7aa2fa3a6ad22ef7def6b84 (patch)
treed8ed1ea0d957afd906556ae89e8622f79c4690f1 /gcc
parent752bf6c80a922e09edf5bcb53e15e08e83057a7f (diff)
parent37415eec77438bba2fc61df3e9a396c1e2cbaca8 (diff)
downloadgcc-9fb06d66cef70584e7aa2fa3a6ad22ef7def6b84.zip
gcc-9fb06d66cef70584e7aa2fa3a6ad22ef7def6b84.tar.gz
gcc-9fb06d66cef70584e7aa2fa3a6ad22ef7def6b84.tar.bz2
Merge #938
938: First pass at declarative macro expansion r=philberty a=philberty This does not support repetition matchers but it supports simple declarative macros and transcribes them. The approach taken here is that we reuse our existing parser to call the apropriate functions as specified as part of the MacroFragmentType enum if the parser does not have errors parsing that item then it must be a match. Then once we match a rule we have a map of the token begin/end offsets for each fragment match, this is then used to adjust and create a new token stream for the macro rule definition so that when we feed it to the parser the tokens are already substituted. The resulting expression or item is then attached to the respective macro invocation and this is then name resolved and used for hir lowering. Fixes #17 #22 Addresses #573 Co-authored-by: Philip Herron <philip.herron@embecosm.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/ast/rust-ast-full-test.cc13
-rw-r--r--gcc/rust/ast/rust-ast.h224
-rw-r--r--gcc/rust/ast/rust-macro.h100
-rw-r--r--gcc/rust/expand/rust-macro-expand.cc632
-rw-r--r--gcc/rust/expand/rust-macro-expand.h148
-rw-r--r--gcc/rust/hir/rust-ast-lower-expr.h10
-rw-r--r--gcc/rust/hir/rust-ast-lower-implitem.h20
-rw-r--r--gcc/rust/hir/rust-ast-lower-item.h10
-rw-r--r--gcc/rust/hir/rust-ast-lower-stmt.h10
-rw-r--r--gcc/rust/lex/rust-lex.h19
-rw-r--r--gcc/rust/parse/rust-parse-impl.h26
-rw-r--r--gcc/rust/parse/rust-parse.cc26
-rw-r--r--gcc/rust/parse/rust-parse.h46
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h7
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-implitem.h21
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-item.h14
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-stmt.h8
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-toplevel.h7
-rw-r--r--gcc/rust/resolve/rust-ast-resolve.cc40
-rw-r--r--gcc/rust/resolve/rust-name-resolver.h9
-rw-r--r--gcc/rust/typecheck/rust-tycheck-dump.h6
-rw-r--r--gcc/rust/util/rust-hir-map.cc20
-rw-r--r--gcc/rust/util/rust-hir-map.h7
-rw-r--r--gcc/testsuite/rust/execute/torture/macros1.rs13
-rw-r--r--gcc/testsuite/rust/execute/torture/macros2.rs40
-rw-r--r--gcc/testsuite/rust/execute/torture/macros3.rs61
-rw-r--r--gcc/testsuite/rust/execute/torture/macros4.rs15
-rw-r--r--gcc/testsuite/rust/execute/torture/macros5.rs13
-rw-r--r--gcc/testsuite/rust/execute/torture/macros6.rs12
-rw-r--r--gcc/testsuite/rust/execute/xfail/macro2.rs30
-rw-r--r--gcc/testsuite/rust/execute/xfail/macro3.rs45
31 files changed, 1383 insertions, 269 deletions
diff --git a/gcc/rust/ast/rust-ast-full-test.cc b/gcc/rust/ast/rust-ast-full-test.cc
index 68f6f8c..3a1e295 100644
--- a/gcc/rust/ast/rust-ast-full-test.cc
+++ b/gcc/rust/ast/rust-ast-full-test.cc
@@ -4387,13 +4387,6 @@ std::vector<std::unique_ptr<Token> >
DelimTokenTree::to_token_stream () const
{
std::vector<std::unique_ptr<Token> > tokens;
-
- // simulate presence of delimiters
- const_TokenPtr left_paren
- = Rust::Token::make (LEFT_PAREN, Linemap::unknown_location ());
- tokens.push_back (
- std::unique_ptr<Token> (new Token (std::move (left_paren))));
-
for (const auto &tree : token_trees)
{
std::vector<std::unique_ptr<Token> > stream = tree->to_token_stream ();
@@ -4402,13 +4395,7 @@ DelimTokenTree::to_token_stream () const
std::make_move_iterator (stream.end ()));
}
- const_TokenPtr right_paren
- = Rust::Token::make (RIGHT_PAREN, Linemap::unknown_location ());
- tokens.push_back (
- std::unique_ptr<Token> (new Token (std::move (right_paren))));
-
tokens.shrink_to_fit ();
-
return tokens;
}
diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h
index ba973f1..e72937e 100644
--- a/gcc/rust/ast/rust-ast.h
+++ b/gcc/rust/ast/rust-ast.h
@@ -22,9 +22,6 @@
#include "rust-system.h"
#include "rust-hir-map.h"
-
-// gccrs imports
-// required for AST::Token
#include "rust-token.h"
#include "rust-location.h"
@@ -32,7 +29,6 @@ namespace Rust {
// TODO: remove typedefs and make actual types for these
typedef std::string Identifier;
typedef int TupleIndex;
-
struct Session;
namespace AST {
@@ -48,34 +44,6 @@ enum DelimType
CURLY
};
-// Base AST node object - TODO is this really required or useful? Where to draw
-// line?
-/*class Node {
- public:
- // Gets node's Location.
- Location get_locus() const {
- return loc;
- }
-
- // Sets node's Location.
- void set_locus(Location loc_) {
- loc = loc_;
- }
-
- // Get node output as a string. Pure virtual.
- virtual std::string as_string() const = 0;
-
- virtual ~Node() {}
-
- // TODO: constructor including Location? Make all derived classes have
-Location?
-
- private:
- // The node's location.
- Location loc;
-};*/
-// decided to not have node as a "node" would never need to be stored
-
// forward decl for use in token tree method
class Token;
@@ -108,6 +76,14 @@ protected:
class MacroMatch
{
public:
+ enum MacroMatchType
+ {
+ Fragment,
+ Repetition,
+ Matcher,
+ Tok
+ };
+
virtual ~MacroMatch () {}
virtual std::string as_string () const = 0;
@@ -121,6 +97,8 @@ public:
virtual void accept_vis (ASTVisitor &vis) = 0;
+ virtual MacroMatchType get_macro_match_type () const = 0;
+
protected:
// pure virtual clone implementation
virtual MacroMatch *clone_macro_match_impl () const = 0;
@@ -234,6 +212,11 @@ public:
// Get a new token pointer copy.
const_TokenPtr get_tok_ptr () const { return tok_ref; }
+ MacroMatchType get_macro_match_type () const override
+ {
+ return MacroMatchType::Tok;
+ }
+
protected:
// No virtual for now as not polymorphic but can be in future
/*virtual*/ Token *clone_token_impl () const { return new Token (*this); }
@@ -788,6 +771,13 @@ public:
{
return AttrInput::AttrInputType::TOKEN_TREE;
}
+
+ std::vector<std::unique_ptr<TokenTree> > &get_token_trees ()
+ {
+ return token_trees;
+ }
+
+ DelimType get_delim_type () const { return delim_type; }
};
/* Forward decl - definition moved to rust-expr.h as it requires LiteralExpr to
@@ -1485,6 +1475,160 @@ public:
}
};
+class SingleASTNode
+{
+public:
+ enum NodeType
+ {
+ EXPRESSION,
+ ITEM,
+ STMT,
+ };
+
+ SingleASTNode (std::unique_ptr<Expr> expr)
+ : type (EXPRESSION), expr (std::move (expr)), item (nullptr), stmt (nullptr)
+ {}
+
+ SingleASTNode (std::unique_ptr<Item> item)
+ : type (ITEM), expr (nullptr), item (std::move (item)), stmt (nullptr)
+ {}
+
+ SingleASTNode (std::unique_ptr<Stmt> stmt)
+ : type (STMT), expr (nullptr), item (nullptr), stmt (std::move (stmt))
+ {}
+
+ SingleASTNode (SingleASTNode const &other)
+ {
+ type = other.type;
+ switch (type)
+ {
+ case EXPRESSION:
+ expr = other.expr->clone_expr ();
+ break;
+
+ case ITEM:
+ item = other.item->clone_item ();
+ break;
+
+ case STMT:
+ stmt = other.stmt->clone_stmt ();
+ break;
+ }
+ }
+
+ SingleASTNode operator= (SingleASTNode const &other)
+ {
+ type = other.type;
+ switch (type)
+ {
+ case EXPRESSION:
+ expr = other.expr->clone_expr ();
+ break;
+
+ case ITEM:
+ item = other.item->clone_item ();
+ break;
+
+ case STMT:
+ stmt = other.stmt->clone_stmt ();
+ break;
+ }
+ return *this;
+ }
+
+ SingleASTNode (SingleASTNode &&other) = default;
+ SingleASTNode &operator= (SingleASTNode &&other) = default;
+
+ std::unique_ptr<Expr> &get_expr ()
+ {
+ rust_assert (type == EXPRESSION);
+ return expr;
+ }
+
+ std::unique_ptr<Item> &get_item ()
+ {
+ rust_assert (type == ITEM);
+ return item;
+ }
+
+ std::unique_ptr<Stmt> &get_stmt ()
+ {
+ rust_assert (type == STMT);
+ return stmt;
+ }
+
+ void accept_vis (ASTVisitor &vis)
+ {
+ switch (type)
+ {
+ case EXPRESSION:
+ expr->accept_vis (vis);
+ break;
+
+ case ITEM:
+ item->accept_vis (vis);
+ break;
+
+ case STMT:
+ stmt->accept_vis (vis);
+ break;
+ }
+ }
+
+private:
+ NodeType type;
+
+ // FIXME make this a union
+ std::unique_ptr<Expr> expr;
+ std::unique_ptr<Item> item;
+ std::unique_ptr<Stmt> stmt;
+};
+
+/* Basically, a "fragment" that can be incorporated into the AST, created as
+ * a result of macro expansion. Really annoying to work with due to the fact
+ * that macros can really expand to anything. As such, horrible representation
+ * at the moment. */
+class ASTFragment
+{
+private:
+ /* basic idea: essentially, a vector of tagged unions of different AST node
+ * types. Now, this could actually be stored without a tagged union if the
+ * different AST node types had a unified parent, but that would create
+ * issues with the diamond problem or significant performance penalties. So
+ * a tagged union had to be used instead. A vector is used to represent the
+ * ability for a macro to expand to two statements, for instance. */
+
+ std::vector<SingleASTNode> nodes;
+
+public:
+ ASTFragment (std::vector<SingleASTNode> nodes) : nodes (std::move (nodes)) {}
+
+ ASTFragment (ASTFragment const &other)
+ {
+ nodes.clear ();
+ nodes.reserve (other.nodes.size ());
+ for (auto &n : other.nodes)
+ {
+ nodes.push_back (n);
+ }
+ }
+
+ ASTFragment &operator= (ASTFragment const &other)
+ {
+ nodes.clear ();
+ nodes.reserve (other.nodes.size ());
+ for (auto &n : other.nodes)
+ {
+ nodes.push_back (n);
+ }
+ return *this;
+ }
+
+ static ASTFragment create_empty () { return ASTFragment ({}); }
+
+ std::vector<SingleASTNode> &get_nodes () { return nodes; }
+};
+
/* A macro invocation item (or statement) AST node (i.e. semi-coloned macro
* invocation) */
class MacroInvocationSemi : public MacroItem,
@@ -1496,6 +1640,10 @@ class MacroInvocationSemi : public MacroItem,
std::vector<Attribute> outer_attrs;
MacroInvocData invoc_data;
Location locus;
+ NodeId node_id;
+
+ // this is the expanded macro
+ ASTFragment fragment;
public:
std::string as_string () const override;
@@ -1503,7 +1651,9 @@ public:
MacroInvocationSemi (MacroInvocData invoc_data,
std::vector<Attribute> outer_attrs, Location locus)
: outer_attrs (std::move (outer_attrs)),
- invoc_data (std::move (invoc_data)), locus (locus)
+ invoc_data (std::move (invoc_data)), locus (locus),
+ node_id (Analysis::Mappings::get ()->get_next_node_id ()),
+ fragment (ASTFragment::create_empty ())
{}
void accept_vis (ASTVisitor &vis) override;
@@ -1527,6 +1677,14 @@ public:
Location get_locus () const override final { return locus; }
+ MacroInvocData &get_invoc_data () { return invoc_data; }
+
+ ASTFragment &get_fragment () { return fragment; }
+
+ void set_fragment (ASTFragment &&f) { fragment = std::move (f); }
+
+ NodeId get_macro_node_id () const { return node_id; }
+
protected:
MacroInvocationSemi *clone_macro_invocation_semi_impl () const
{
diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h
index e0524c6..b5370d8 100644
--- a/gcc/rust/ast/rust-macro.h
+++ b/gcc/rust/ast/rust-macro.h
@@ -24,6 +24,7 @@
namespace Rust {
namespace AST {
+
// Decls as definitions moved to rust-ast.h
class MacroItem;
class MacroInvocationSemi;
@@ -109,6 +110,14 @@ public:
void accept_vis (ASTVisitor &vis) override;
+ MacroMatchType get_macro_match_type () const override
+ {
+ return MacroMatchType::Fragment;
+ }
+
+ Identifier get_ident () const { return ident; }
+ MacroFragSpec get_frag_spec () const { return frag_spec; }
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
@@ -192,6 +201,11 @@ public:
void accept_vis (ASTVisitor &vis) override;
+ MacroMatchType get_macro_match_type () const override
+ {
+ return MacroMatchType::Repetition;
+ }
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
@@ -259,6 +273,14 @@ public:
void accept_vis (ASTVisitor &vis) override;
+ MacroMatchType get_macro_match_type () const override
+ {
+ return MacroMatchType::Matcher;
+ }
+
+ DelimType get_delim_type () const { return delim_type; }
+ std::vector<std::unique_ptr<MacroMatch> > &get_matches () { return matches; }
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
@@ -288,6 +310,8 @@ public:
std::string as_string () const { return token_tree.as_string (); }
Location get_locus () const { return locus; }
+
+ DelimTokenTree &get_token_tree () { return token_tree; }
};
// A macro rule? Matcher and transcriber pair?
@@ -319,6 +343,9 @@ public:
Location get_locus () const { return locus; }
std::string as_string () const;
+
+ MacroMatcher &get_matcher () { return matcher; }
+ MacroTranscriber &get_transcriber () { return transcriber; }
};
// A macro rules definition item AST node
@@ -365,6 +392,11 @@ public:
Location get_locus () const override final { return locus; }
+ Identifier get_rule_name () const { return rule_name; }
+
+ std::vector<MacroRule> &get_rules () { return rules; }
+ const std::vector<MacroRule> &get_rules () const { return rules; }
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
@@ -384,13 +416,17 @@ class MacroInvocation : public TypeNoBounds,
MacroInvocData invoc_data;
Location locus;
+ // this is the expanded macro
+ ASTFragment fragment;
+
public:
std::string as_string () const override;
MacroInvocation (MacroInvocData invoc_data,
std::vector<Attribute> outer_attrs, Location locus)
: outer_attrs (std::move (outer_attrs)),
- invoc_data (std::move (invoc_data)), locus (locus)
+ invoc_data (std::move (invoc_data)), locus (locus),
+ fragment (ASTFragment::create_empty ())
{}
Location get_locus () const override final { return locus; }
@@ -417,6 +453,12 @@ public:
return ExprWithoutBlock::get_node_id ();
}
+ MacroInvocData &get_invoc_data () { return invoc_data; }
+
+ ASTFragment &get_fragment () { return fragment; }
+
+ void set_fragment (ASTFragment &&f) { fragment = std::move (f); }
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
@@ -651,62 +693,6 @@ protected:
}
};
-/* Should be a tagged union to save space but implemented as struct due to
- * technical difficulties. TODO: fix
- * Basically, a single AST node used inside an AST fragment. */
-struct SingleASTNode
-{
- std::unique_ptr<Expr> expr;
- std::unique_ptr<Stmt> stmt;
- std::unique_ptr<Item> item;
- std::unique_ptr<Type> type;
- std::unique_ptr<Pattern> pattern;
- std::unique_ptr<TraitItem> trait_item;
- std::unique_ptr<InherentImplItem> inherent_impl_item;
- std::unique_ptr<TraitImplItem> trait_impl_item;
- std::unique_ptr<ExternalItem> external_item;
-
- SingleASTNode (std::unique_ptr<Expr> expr) : expr (std::move (expr)) {}
- SingleASTNode (std::unique_ptr<Stmt> stmt) : stmt (std::move (stmt)) {}
- SingleASTNode (std::unique_ptr<Item> item) : item (std::move (item)) {}
- SingleASTNode (std::unique_ptr<Type> type) : type (std::move (type)) {}
- SingleASTNode (std::unique_ptr<Pattern> pattern)
- : pattern (std::move (pattern))
- {}
- SingleASTNode (std::unique_ptr<TraitItem> trait_item)
- : trait_item (std::move (trait_item))
- {}
- SingleASTNode (std::unique_ptr<InherentImplItem> inherent_impl_item)
- : inherent_impl_item (std::move (inherent_impl_item))
- {}
- SingleASTNode (std::unique_ptr<TraitImplItem> trait_impl_item)
- : trait_impl_item (std::move (trait_impl_item))
- {}
- SingleASTNode (std::unique_ptr<ExternalItem> external_item)
- : external_item (std::move (external_item))
- {}
-};
-
-/* Basically, a "fragment" that can be incorporated into the AST, created as
- * a result of macro expansion. Really annoying to work with due to the fact
- * that macros can really expand to anything. As such, horrible representation
- * at the moment. */
-struct ASTFragment
-{
-private:
- /* basic idea: essentially, a vector of tagged unions of different AST node
- * types. Now, this could actually be stored without a tagged union if the
- * different AST node types had a unified parent, but that would create
- * issues with the diamond problem or significant performance penalties. So
- * a tagged union had to be used instead. A vector is used to represent the
- * ability for a macro to expand to two statements, for instance. */
-
- std::vector<SingleASTNode> nodes;
-
-public:
- ASTFragment (std::vector<SingleASTNode> nodes) : nodes (std::move (nodes)) {}
-};
-
// Object that parses macros from a token stream.
/* TODO: would "AttributeParser" be a better name? MetaItems are only for
* attributes, I believe */
diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc
index 4a096c3..dcfec7c 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -20,6 +20,7 @@
#include "rust-ast-full.h"
#include "rust-ast-visitor.h"
#include "rust-diagnostics.h"
+#include "rust-parse.h"
namespace Rust {
// Visitor used to expand attributes.
@@ -323,6 +324,13 @@ public:
// I don't think any macro token trees can be stripped in any way
// TODO: maybe have cfg! macro stripping behaviour here?
+
+ expander.expand_invoc_semi (macro_invoc);
+
+ // we need to visit the expanded fragments since it may need cfg expansion
+ // and it may be recursive
+ for (auto &node : macro_invoc.get_fragment ().get_nodes ())
+ node.accept_vis (*this);
}
void visit (AST::PathInExpression &path) override
@@ -1033,13 +1041,17 @@ public:
"cannot strip expression in this position - outer "
"attributes not allowed");
}
+
void visit (AST::BlockExpr &expr) override
{
+ expander.push_context (MacroExpander::BLOCK);
+
// initial strip test based on outer attrs
expander.expand_cfg_attrs (expr.get_outer_attrs ());
if (expander.fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
+ expander.pop_context ();
return;
}
@@ -1049,6 +1061,7 @@ public:
if (expander.fails_cfg_with_expand (expr.get_inner_attrs ()))
{
expr.mark_for_strip ();
+ expander.pop_context ();
return;
}
@@ -1065,7 +1078,9 @@ public:
if (tail_expr->is_marked_for_strip ())
expr.strip_tail_expr ();
}
+ expander.pop_context ();
}
+
void visit (AST::ClosureExprInnerTyped &expr) override
{
// initial strip test based on outer attrs
@@ -2509,9 +2524,20 @@ public:
}
// I don't think any macro rules can be stripped in any way
+
+ auto path = Resolver::CanonicalPath::new_seg (rules_def.get_node_id (),
+ rules_def.get_rule_name ());
+ expander.resolver->get_macro_scope ().insert (path,
+ rules_def.get_node_id (),
+ rules_def.get_locus ());
+ expander.mappings->insert_macro_def (&rules_def);
}
+
void visit (AST::MacroInvocation &macro_invoc) override
{
+ // FIXME
+ // we probably need another recurision check here
+
// initial strip test based on outer attrs
expander.expand_cfg_attrs (macro_invoc.get_outer_attrs ());
if (expander.fails_cfg_with_expand (macro_invoc.get_outer_attrs ()))
@@ -2521,9 +2547,14 @@ public:
}
// I don't think any macro token trees can be stripped in any way
+ expander.expand_invoc (macro_invoc);
- // TODO: maybe have stripping behaviour for the cfg! macro here?
+ // we need to visit the expanded fragments since it may need cfg expansion
+ // and it may be recursive
+ for (auto &node : macro_invoc.get_fragment ().get_nodes ())
+ node.accept_vis (*this);
}
+
void visit (AST::MetaItemPath &) override {}
void visit (AST::MetaItemSeq &) override {}
void visit (AST::MetaWord &) override {}
@@ -3011,7 +3042,7 @@ MacroExpander::parse_macro_to_meta_item (AST::MacroInvocData &invoc)
}
else
{
- std::vector<std::unique_ptr<AST::MetaItemInner> > meta_items (
+ std::vector<std::unique_ptr<AST::MetaItemInner>> meta_items (
std::move (converted_input->get_items ()));
invoc.set_meta_item_output (std::move (meta_items));
}
@@ -3038,10 +3069,11 @@ MacroExpander::expand_cfg_macro (AST::MacroInvocData &invoc)
return AST::Literal ("false", AST::Literal::BOOL, CORETYPE_BOOL);
}
-#if 0
AST::ASTFragment
-MacroExpander::expand_decl_macro (AST::MacroInvocData &invoc,
- AST::MacroRulesDefinition &rules_def)
+MacroExpander::expand_decl_macro (Location invoc_locus,
+ AST::MacroInvocData &invoc,
+ AST::MacroRulesDefinition &rules_def,
+ bool semicolon)
{
// ensure that both invocation and rules are in a valid state
rust_assert (!invoc.is_marked_for_strip ());
@@ -3081,49 +3113,123 @@ MacroExpander::expand_decl_macro (AST::MacroInvocData &invoc,
* TokenTree). This will prevent re-conversion of Tokens between each type
* all the time, while still allowing the heterogenous storage of token trees.
*/
+
+ AST::DelimTokenTree &invoc_token_tree = invoc.get_delim_tok_tree ();
+
+ // find matching arm
+ AST::MacroRule *matched_rule = nullptr;
+ std::map<std::string, MatchedFragment> matched_fragments;
+ for (auto &rule : rules_def.get_rules ())
+ {
+ sub_stack.push ();
+ bool did_match_rule = try_match_rule (rule, invoc_token_tree);
+ matched_fragments = sub_stack.pop ();
+
+ if (did_match_rule)
+ {
+ matched_rule = &rule;
+ break;
+ }
+ }
+
+ if (matched_rule == nullptr)
+ {
+ RichLocation r (invoc_locus);
+ r.add_range (rules_def.get_locus ());
+ rust_error_at (r, "Failed to match any rule within macro");
+ return AST::ASTFragment::create_empty ();
+ }
+
+ return transcribe_rule (*matched_rule, invoc_token_tree, matched_fragments,
+ semicolon, peek_context ());
+}
+
+void
+MacroExpander::expand_invoc (AST::MacroInvocation &invoc)
+{
+ if (depth_exceeds_recursion_limit ())
+ {
+ rust_error_at (invoc.get_locus (), "reached recursion limit");
+ return;
+ }
+
+ AST::MacroInvocData &invoc_data = invoc.get_invoc_data ();
+
+ // ??
+ // 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;
+ bool found = resolver->get_macro_scope ().lookup (
+ Resolver::CanonicalPath::new_seg (invoc.get_pattern_node_id (),
+ invoc_data.get_path ().as_string ()),
+ &resolved_node);
+ if (!found)
+ {
+ rust_error_at (invoc.get_locus (), "unknown macro");
+ return;
+ }
+
+ // lookup the rules
+ AST::MacroRulesDefinition *rules_def = nullptr;
+ bool ok = mappings->lookup_macro_def (resolved_node, &rules_def);
+ rust_assert (ok);
+
+ auto fragment
+ = expand_decl_macro (invoc.get_locus (), invoc_data, *rules_def, false);
+
+ // lets attach this fragment to the invocation
+ invoc.set_fragment (std::move (fragment));
}
-#endif
void
-MacroExpander::expand_invoc (std::unique_ptr<AST::MacroInvocation> &invoc)
+MacroExpander::expand_invoc_semi (AST::MacroInvocationSemi &invoc)
{
- /* if current expansion depth > recursion limit, create an error (maybe fatal
- * error) and return */
-
- /* 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*/
-
-#if 0
- // macro_rules macro test code
- auto rule_def = find_rules_def(invoc->get_path());
- if (rule_def != nullptr) {
- ASTFrag expanded = expand_decl_macro(invoc, rule_def);
- /* could make this a data structure containing vectors of exprs, patterns and types (for regular),
- * and then stmts and items (for semi). Except what about having an expr, then a type? Hmm. Might
- * have to do the "unified base type" thing OR just have a simulated union, and then have AST frag
- * be a vector of these simulated unions. */
-
- // how would errors be signalled? null fragment? something else?
- // what about error vs just not having stuff in rules definition yet?
-
- /* replace macro invocation with ast frag. actually, don't have any context here. maybe attach ast
- * frag to macro invocation, and then have a method above get it? Or just return the ast frag from
- * this method. */
- }
-#endif
+ if (depth_exceeds_recursion_limit ())
+ {
+ rust_error_at (invoc.get_locus (), "reached recursion limit");
+ return;
+ }
+
+ AST::MacroInvocData &invoc_data = invoc.get_invoc_data ();
+
+ // lookup the rules for this macro
+ NodeId resolved_node = UNKNOWN_NODEID;
+ bool found = resolver->get_macro_scope ().lookup (
+ Resolver::CanonicalPath::new_seg (invoc.get_macro_node_id (),
+ invoc_data.get_path ().as_string ()),
+ &resolved_node);
+ if (!found)
+ {
+ rust_error_at (invoc.get_locus (), "unknown macro");
+ return;
+ }
+
+ // lookup the rules
+ AST::MacroRulesDefinition *rules_def = nullptr;
+ bool ok = mappings->lookup_macro_def (resolved_node, &rules_def);
+ rust_assert (ok);
+
+ auto fragment
+ = expand_decl_macro (invoc.get_locus (), invoc_data, *rules_def, true);
+
+ // lets attach this fragment to the invocation
+ invoc.set_fragment (std::move (fragment));
}
/* Determines whether any cfg predicate is false and hence item with attributes
@@ -3225,6 +3331,9 @@ MacroExpander::expand_cfg_attrs (AST::AttrVec &attrs)
void
MacroExpander::expand_crate ()
{
+ NodeId scope_node_id = crate.get_node_id ();
+ resolver->get_macro_scope ().push (scope_node_id);
+
/* fill macro/decorator map from init list? not sure where init list comes
* from? */
@@ -3242,6 +3351,8 @@ MacroExpander::expand_crate ()
}
// expand module attributes?
+ push_context (ITEM);
+
// expand attributes recursively and strip items if required
AttrVisitor attr_visitor (*this);
auto &items = crate.items;
@@ -3258,6 +3369,8 @@ MacroExpander::expand_crate ()
++it;
}
+ pop_context ();
+
// TODO: should recursive attribute and macro expansion be done in the same
// transversal? Or in separate ones like currently?
@@ -3267,4 +3380,435 @@ MacroExpander::expand_crate ()
// extract exported macros?
}
+
+bool
+MacroExpander::depth_exceeds_recursion_limit () const
+{
+ return expansion_depth >= cfg.recursion_limit;
+}
+
+bool
+MacroExpander::try_match_rule (AST::MacroRule &match_rule,
+ AST::DelimTokenTree &invoc_token_tree)
+{
+ MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
+ Parser<MacroInvocLexer> parser (std::move (lex));
+
+ AST::MacroMatcher &matcher = match_rule.get_matcher ();
+
+ expansion_depth++;
+ if (!match_matcher (parser, matcher))
+ {
+ expansion_depth--;
+ return false;
+ }
+ expansion_depth--;
+
+ bool used_all_input_tokens = parser.skip_token (END_OF_FILE);
+ return used_all_input_tokens;
+}
+
+bool
+MacroExpander::match_fragment (Parser<MacroInvocLexer> &parser,
+ AST::MacroMatchFragment &fragment)
+{
+ switch (fragment.get_frag_spec ())
+ {
+ case AST::MacroFragSpec::EXPR:
+ parser.parse_expr ();
+ break;
+
+ case AST::MacroFragSpec::BLOCK:
+ parser.parse_block_expr ();
+ break;
+
+ case AST::MacroFragSpec::IDENT:
+ parser.parse_identifier_pattern ();
+ break;
+
+ case AST::MacroFragSpec::LITERAL:
+ parser.parse_literal_expr ();
+ break;
+
+ case AST::MacroFragSpec::ITEM:
+ parser.parse_item (false);
+ break;
+
+ case AST::MacroFragSpec::TY:
+ parser.parse_type ();
+ break;
+
+ case AST::MacroFragSpec::PAT:
+ parser.parse_pattern ();
+ break;
+
+ case AST::MacroFragSpec::PATH:
+ parser.parse_path_in_expression ();
+ break;
+
+ case AST::MacroFragSpec::VIS:
+ parser.parse_visibility ();
+ break;
+
+ case AST::MacroFragSpec::STMT:
+ parser.parse_stmt ();
+ break;
+
+ case AST::MacroFragSpec::LIFETIME:
+ parser.parse_lifetime_params ();
+ break;
+
+ // is meta attributes?
+ case AST::MacroFragSpec::META:
+ // parser.parse_inner_attribute ?
+ // parser.parse_outer_attribute ?
+ // parser.parse_attribute_body ?
+ // parser.parse_doc_comment ?
+ gcc_unreachable ();
+ break;
+
+ // what is TT?
+ case AST::MacroFragSpec::TT:
+ // parser.parse_token_tree() ?
+ gcc_unreachable ();
+ break;
+
+ // i guess we just ignore invalid and just error out
+ case AST::MacroFragSpec::INVALID:
+ return false;
+ }
+
+ // it matches if the parser did not produce errors trying to parse that type
+ // of item
+ return !parser.has_errors ();
+}
+
+bool
+MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
+ AST::MacroMatcher &matcher)
+{
+ if (depth_exceeds_recursion_limit ())
+ {
+ rust_error_at (matcher.get_match_locus (), "reached recursion limit");
+ return false;
+ }
+
+ // this is used so we can check that we delimit the stream correctly.
+ switch (matcher.get_delim_type ())
+ {
+ case AST::DelimType::PARENS: {
+ if (!parser.skip_token (LEFT_PAREN))
+ return false;
+ }
+ break;
+
+ case AST::DelimType::SQUARE: {
+ if (!parser.skip_token (LEFT_SQUARE))
+ return false;
+ }
+ break;
+
+ case AST::DelimType::CURLY: {
+ if (!parser.skip_token (LEFT_CURLY))
+ return false;
+ }
+ break;
+ }
+
+ const MacroInvocLexer &source = parser.get_token_source ();
+
+ for (auto &match : matcher.get_matches ())
+ {
+ size_t offs_begin = source.get_offs ();
+ switch (match->get_macro_match_type ())
+ {
+ case AST::MacroMatch::MacroMatchType::Fragment: {
+ AST::MacroMatchFragment *fragment
+ = static_cast<AST::MacroMatchFragment *> (match.get ());
+ if (!match_fragment (parser, *fragment))
+ return false;
+
+ // matched fragment get the offset in the token stream
+ size_t offs_end = source.get_offs ();
+ sub_stack.peek ().insert (
+ {fragment->get_ident (),
+ {fragment->get_ident (), offs_begin, offs_end}});
+ }
+ break;
+
+ case AST::MacroMatch::MacroMatchType::Tok: {
+ AST::Token *tok = static_cast<AST::Token *> (match.get ());
+ if (!match_token (parser, *tok))
+ return false;
+ }
+ break;
+
+ case AST::MacroMatch::MacroMatchType::Repetition: {
+ AST::MacroMatchRepetition *rep
+ = static_cast<AST::MacroMatchRepetition *> (match.get ());
+ if (!match_repetition (parser, *rep))
+ return false;
+ }
+ break;
+
+ case AST::MacroMatch::MacroMatchType::Matcher: {
+ AST::MacroMatcher *m
+ = static_cast<AST::MacroMatcher *> (match.get ());
+ expansion_depth++;
+ if (!match_matcher (parser, *m))
+ {
+ expansion_depth--;
+ return false;
+ }
+ expansion_depth--;
+ }
+ break;
+ }
+ }
+
+ switch (matcher.get_delim_type ())
+ {
+ case AST::DelimType::PARENS: {
+ if (!parser.skip_token (RIGHT_PAREN))
+ return false;
+ }
+ break;
+
+ case AST::DelimType::SQUARE: {
+ if (!parser.skip_token (RIGHT_SQUARE))
+ return false;
+ }
+ break;
+
+ case AST::DelimType::CURLY: {
+ if (!parser.skip_token (RIGHT_CURLY))
+ return false;
+ }
+ break;
+ }
+
+ return true;
+}
+
+bool
+MacroExpander::match_token (Parser<MacroInvocLexer> &parser, AST::Token &token)
+{
+ // FIXME this needs to actually match the content and the type
+ return parser.skip_token (token.get_id ());
+}
+
+bool
+MacroExpander::match_repetition (Parser<MacroInvocLexer> &parser,
+ AST::MacroMatchRepetition &rep)
+{
+ // TODO
+ gcc_unreachable ();
+ return false;
+}
+
+AST::ASTFragment
+MacroExpander::transcribe_rule (
+ AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree,
+ std::map<std::string, MatchedFragment> &matched_fragments, bool semicolon,
+ ContextType ctx)
+{
+ // we can manipulate the token tree to substitute the dollar identifiers so
+ // that when we call parse its already substituted for us
+ AST::MacroTranscriber &transcriber = match_rule.get_transcriber ();
+ AST::DelimTokenTree &transcribe_tree = transcriber.get_token_tree ();
+
+ auto invoc_stream = invoc_token_tree.to_token_stream ();
+ auto macro_rule_tokens = transcribe_tree.to_token_stream ();
+
+ std::vector<std::unique_ptr<AST::Token>> substituted_tokens
+ = substitute_tokens (invoc_stream, macro_rule_tokens, matched_fragments);
+
+ // // handy for debugging
+ // for (auto &tok : substituted_tokens)
+ // {
+ // rust_debug ("tok: [%s]", tok->as_string ().c_str ());
+ // }
+
+ // parse it to an ASTFragment
+ MacroInvocLexer lex (std::move (substituted_tokens));
+ Parser<MacroInvocLexer> parser (std::move (lex));
+
+ // this is used so we can check that we delimit the stream correctly.
+ switch (transcribe_tree.get_delim_type ())
+ {
+ case AST::DelimType::PARENS:
+ rust_assert (parser.skip_token (LEFT_PAREN));
+ break;
+
+ case AST::DelimType::CURLY:
+ rust_assert (parser.skip_token (LEFT_CURLY));
+ break;
+
+ case AST::DelimType::SQUARE:
+ rust_assert (parser.skip_token (LEFT_SQUARE));
+ break;
+ }
+
+ // see https://github.com/Rust-GCC/gccrs/issues/22
+ // TL;DR:
+ // - Treat all macro invocations with parentheses, (), or square brackets,
+ // [], as expressions.
+ // - If the macro invocation has curly brackets, {}, it may be parsed as a
+ // statement depending on the context.
+ // - If the macro invocation has a semicolon at the end, it must be parsed
+ // as a statement (either via ExpressionStatement or
+ // MacroInvocationWithSemi)
+
+ // parse the item
+ std::vector<AST::SingleASTNode> nodes;
+ switch (invoc_token_tree.get_delim_type ())
+ {
+ case AST::DelimType::PARENS:
+ case AST::DelimType::SQUARE: {
+ switch (ctx)
+ {
+ case ContextType::ITEM: {
+ auto item = parser.parse_item (true);
+ if (item != nullptr && !parser.has_errors ())
+ {
+ rust_debug ("HELLO WORLD: [%s]", item->as_string ().c_str ());
+ nodes.push_back (std::move (item));
+ }
+ }
+ break;
+
+ case ContextType::BLOCK: {
+ auto expr = parser.parse_expr ();
+ if (expr != nullptr && !parser.has_errors ())
+ nodes.push_back (std::move (expr));
+ }
+ break;
+ }
+ }
+ break;
+
+ case AST::DelimType::CURLY: {
+ switch (ctx)
+ {
+ case ContextType::ITEM: {
+ auto item = parser.parse_item (true);
+ if (item != nullptr && !parser.has_errors ())
+ nodes.push_back (std::move (item));
+ }
+ break;
+
+ case ContextType::BLOCK: {
+ auto stmt = parser.parse_stmt ();
+ if (stmt != nullptr && !parser.has_errors ())
+ nodes.push_back (std::move (stmt));
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ // emit any errors
+ if (parser.has_errors ())
+ {
+ for (auto &err : parser.get_errors ())
+ {
+ rust_error_at (err.locus, "%s", err.message.c_str ());
+ }
+ return AST::ASTFragment::create_empty ();
+ }
+
+ // are all the tokens used?
+ bool did_delimit = false;
+ switch (transcribe_tree.get_delim_type ())
+ {
+ case AST::DelimType::PARENS:
+ did_delimit = parser.skip_token (RIGHT_PAREN);
+ break;
+ case AST::DelimType::SQUARE:
+ did_delimit = parser.skip_token (RIGHT_SQUARE);
+ break;
+ case AST::DelimType::CURLY:
+ did_delimit = parser.skip_token (RIGHT_CURLY);
+ break;
+ }
+
+ bool reached_end_of_stream = did_delimit && parser.skip_token (END_OF_FILE);
+ if (!reached_end_of_stream)
+ {
+ const_TokenPtr current_token = parser.peek_current_token ();
+ rust_error_at (current_token->get_locus (),
+ "tokens here and after are unparsed");
+ }
+
+ return AST::ASTFragment (std::move (nodes));
+}
+
+std::vector<std::unique_ptr<AST::Token>>
+MacroExpander::substitute_tokens (
+ std::vector<std::unique_ptr<AST::Token>> &input,
+ std::vector<std::unique_ptr<AST::Token>> &macro,
+ std::map<std::string, MatchedFragment> &fragments)
+{
+ std::vector<std::unique_ptr<AST::Token>> replaced_tokens;
+
+ for (size_t i = 0; i < macro.size (); i++)
+ {
+ auto &tok = macro.at (i);
+ if (tok->get_id () == DOLLAR_SIGN)
+ {
+ std::vector<std::unique_ptr<AST::Token>> parsed_toks;
+
+ std::string ident;
+ for (size_t offs = i; i < macro.size (); offs++)
+ {
+ auto &tok = macro.at (offs);
+ if (tok->get_id () == DOLLAR_SIGN && offs == i)
+ {
+ parsed_toks.push_back (tok->clone_token ());
+ }
+ else if (tok->get_id () == IDENTIFIER)
+ {
+ rust_assert (tok->as_string ().size () == 1);
+ ident.push_back (tok->as_string ().at (0));
+ parsed_toks.push_back (tok->clone_token ());
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // lookup the ident
+ auto it = fragments.find (ident);
+ if (it == fragments.end ())
+ {
+ // just leave the tokens in
+ for (auto &tok : parsed_toks)
+ {
+ replaced_tokens.push_back (tok->clone_token ());
+ }
+ }
+ else
+ {
+ // replace
+ MatchedFragment &frag = it->second;
+ for (size_t offs = frag.token_offset_begin;
+ offs < frag.token_offset_end; offs++)
+ {
+ auto &tok = input.at (offs);
+ replaced_tokens.push_back (tok->clone_token ());
+ }
+ }
+ i += parsed_toks.size () - 1;
+ }
+ else
+ {
+ replaced_tokens.push_back (tok->clone_token ());
+ }
+ }
+
+ return replaced_tokens;
+}
+
} // namespace Rust
diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h
index cd9165a..d8a2d50 100644
--- a/gcc/rust/expand/rust-macro-expand.h
+++ b/gcc/rust/expand/rust-macro-expand.h
@@ -19,8 +19,13 @@
#ifndef RUST_MACRO_EXPAND_H
#define RUST_MACRO_EXPAND_H
+#include "rust-buffered-queue.h"
+#include "rust-parse.h"
+#include "rust-token.h"
#include "rust-ast.h"
#include "rust-macro.h"
+#include "rust-hir-map.h"
+#include "rust-name-resolver.h"
// Provides objects and method prototypes for macro expansion
@@ -43,14 +48,101 @@ struct ExpansionCfg
std::string crate_name = "";
};
+class MacroInvocLexer
+{
+public:
+ MacroInvocLexer (std::vector<std::unique_ptr<AST::Token>> stream)
+ : offs (0), token_stream (std::move (stream))
+ {}
+
+ // Returns token n tokens ahead of current position.
+ const_TokenPtr peek_token (int n)
+ {
+ if ((offs + n) >= token_stream.size ())
+ return Token::make (END_OF_FILE, Location ());
+
+ return token_stream.at (offs + n)->get_tok_ptr ();
+ }
+ // Peeks the current token.
+ const_TokenPtr peek_token () { return peek_token (0); }
+
+ // Advances current token to n + 1 tokens ahead of current position.
+ void skip_token (int n) { offs += (n + 1); }
+
+ // Skips the current token.
+ void skip_token () { skip_token (0); }
+
+ // Splits the current token into two. Intended for use with nested generics
+ // closes (i.e. T<U<X>> where >> is wrongly lexed as one token). Note that
+ // this will only work with "simple" tokens like punctuation.
+ void split_current_token (TokenId /*new_left*/, TokenId /*new_right*/)
+ {
+ // FIXME
+ gcc_unreachable ();
+ }
+
+ std::string get_filename () const
+ {
+ gcc_unreachable ();
+ return "FIXME";
+ }
+
+ size_t get_offs () const { return offs; }
+
+private:
+ size_t offs;
+ std::vector<std::unique_ptr<AST::Token>> token_stream;
+};
+
+struct MatchedFragment
+{
+ std::string fragment_ident;
+ size_t token_offset_begin;
+ size_t token_offset_end;
+
+ std::string as_string () const
+ {
+ return fragment_ident + "=" + std::to_string (token_offset_begin) + ":"
+ + std::to_string (token_offset_end);
+ }
+};
+
+class SubstitutionScope
+{
+public:
+ SubstitutionScope () : stack () {}
+
+ void push () { stack.push_back ({}); }
+
+ std::map<std::string, MatchedFragment> pop ()
+ {
+ auto top = stack.back ();
+ stack.pop_back ();
+ return top;
+ }
+
+ std::map<std::string, MatchedFragment> &peek () { return stack.back (); }
+
+private:
+ std::vector<std::map<std::string, MatchedFragment>> stack;
+};
+
// Object used to store shared data (between functions) for macro expansion.
struct MacroExpander
{
+ enum ContextType
+ {
+ ITEM,
+ BLOCK,
+ };
+
ExpansionCfg cfg;
unsigned int expansion_depth = 0;
MacroExpander (AST::Crate &crate, ExpansionCfg cfg, Session &session)
- : cfg (cfg), crate (crate), session (session)
+ : cfg (cfg), crate (crate), session (session),
+ sub_stack (SubstitutionScope ()), resolver (Resolver::Resolver::get ()),
+ mappings (Analysis::Mappings::get ())
{}
~MacroExpander () = default;
@@ -61,11 +153,14 @@ struct MacroExpander
/* Expands a macro invocation (not macro invocation semi) - possibly make both
* have similar duck-typed interface and use templates?*/
// should this be public or private?
- void expand_invoc (std::unique_ptr<AST::MacroInvocation> &invoc);
+ void expand_invoc (AST::MacroInvocation &invoc);
+ void expand_invoc_semi (AST::MacroInvocationSemi &invoc);
// Expands a single declarative macro.
- AST::ASTFragment expand_decl_macro (AST::MacroInvocData &invoc,
- AST::MacroRulesDefinition &rules_def);
+ AST::ASTFragment expand_decl_macro (Location locus,
+ AST::MacroInvocData &invoc,
+ AST::MacroRulesDefinition &rules_def,
+ bool semicolon);
void expand_cfg_attrs (AST::AttrVec &attrs);
bool fails_cfg (const AST::AttrVec &attr) const;
@@ -76,10 +171,55 @@ struct MacroExpander
// Get the literal representation of a cfg! macro.
AST::Literal expand_cfg_macro (AST::MacroInvocData &invoc);
+ bool depth_exceeds_recursion_limit () const;
+
+ bool try_match_rule (AST::MacroRule &match_rule,
+ AST::DelimTokenTree &invoc_token_tree);
+
+ AST::ASTFragment
+ transcribe_rule (AST::MacroRule &match_rule,
+ AST::DelimTokenTree &invoc_token_tree,
+ std::map<std::string, MatchedFragment> &matched_fragments,
+ bool semicolon, ContextType ctx);
+
+ bool match_fragment (Parser<MacroInvocLexer> &parser,
+ AST::MacroMatchFragment &fragment);
+
+ bool match_token (Parser<MacroInvocLexer> &parser, AST::Token &token);
+
+ bool match_repetition (Parser<MacroInvocLexer> &parser,
+ AST::MacroMatchRepetition &rep);
+
+ bool match_matcher (Parser<MacroInvocLexer> &parser,
+ AST::MacroMatcher &matcher);
+
+ static std::vector<std::unique_ptr<AST::Token>>
+ substitute_tokens (std::vector<std::unique_ptr<AST::Token>> &input,
+ std::vector<std::unique_ptr<AST::Token>> &macro,
+ std::map<std::string, MatchedFragment> &fragments);
+
+ void push_context (ContextType t) { context.push_back (t); }
+
+ ContextType pop_context ()
+ {
+ ContextType t = context.back ();
+ context.pop_back ();
+ return t;
+ }
+
+ ContextType peek_context () { return context.back (); }
+
private:
AST::Crate &crate;
Session &session;
+ SubstitutionScope sub_stack;
+ std::vector<ContextType> context;
+
+public:
+ Resolver::Resolver *resolver;
+ Analysis::Mappings *mappings;
};
+
} // namespace Rust
#endif
diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h
index 1cc3f1d..a8048bb 100644
--- a/gcc/rust/hir/rust-ast-lower-expr.h
+++ b/gcc/rust/hir/rust-ast-lower-expr.h
@@ -100,6 +100,16 @@ public:
return resolver.translated;
}
+ void visit (AST::MacroInvocation &expr) override
+ {
+ AST::ASTFragment &fragment = expr.get_fragment ();
+
+ // FIXME
+ // this assertion might go away, maybe on failure's to expand a macro?
+ rust_assert (!fragment.get_nodes ().empty ());
+ fragment.get_nodes ().at (0).accept_vis (*this);
+ }
+
void visit (AST::TupleIndexExpr &expr) override
{
HIR::Expr *tuple_expr
diff --git a/gcc/rust/hir/rust-ast-lower-implitem.h b/gcc/rust/hir/rust-ast-lower-implitem.h
index c9dfd1b..3d10b70 100644
--- a/gcc/rust/hir/rust-ast-lower-implitem.h
+++ b/gcc/rust/hir/rust-ast-lower-implitem.h
@@ -52,6 +52,16 @@ public:
return resolver.translated;
}
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+
+ // FIXME
+ // this assertion might go away, maybe on failure's to expand a macro?
+ rust_assert (!fragment.get_nodes ().empty ());
+ fragment.get_nodes ().at (0).accept_vis (*this);
+ }
+
void visit (AST::TypeAlias &alias) override
{
std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
@@ -308,6 +318,16 @@ public:
return resolver.translated;
}
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+
+ // FIXME
+ // this assertion might go away, maybe on failure's to expand a macro?
+ rust_assert (!fragment.get_nodes ().empty ());
+ fragment.get_nodes ().at (0).accept_vis (*this);
+ }
+
void visit (AST::TraitItemFunc &func) override
{
AST::TraitFunctionDecl &ref = func.get_trait_function_decl ();
diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h
index d4b5910..30bd896 100644
--- a/gcc/rust/hir/rust-ast-lower-item.h
+++ b/gcc/rust/hir/rust-ast-lower-item.h
@@ -47,6 +47,16 @@ public:
return resolver.translated;
}
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+
+ // FIXME
+ // this assertion might go away, maybe on failure's to expand a macro?
+ rust_assert (!fragment.get_nodes ().empty ());
+ fragment.get_nodes ().at (0).accept_vis (*this);
+ }
+
void visit (AST::Module &module) override
{
auto crate_num = mappings->get_current_crate ();
diff --git a/gcc/rust/hir/rust-ast-lower-stmt.h b/gcc/rust/hir/rust-ast-lower-stmt.h
index ede72bd..b25246a 100644
--- a/gcc/rust/hir/rust-ast-lower-stmt.h
+++ b/gcc/rust/hir/rust-ast-lower-stmt.h
@@ -45,6 +45,16 @@ public:
return resolver.translated;
}
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+
+ // FIXME
+ // this assertion might go away, maybe on failure's to expand a macro?
+ rust_assert (!fragment.get_nodes ().empty ());
+ fragment.get_nodes ().at (0).accept_vis (*this);
+ }
+
void visit (AST::ExprStmtWithBlock &stmt) override
{
HIR::ExprWithBlock *expr
diff --git a/gcc/rust/lex/rust-lex.h b/gcc/rust/lex/rust-lex.h
index 4b2feae..0ae07fe 100644
--- a/gcc/rust/lex/rust-lex.h
+++ b/gcc/rust/lex/rust-lex.h
@@ -1,3 +1,21 @@
+// Copyright (C) 2020-2022 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_LEX_H
#define RUST_LEX_H
@@ -198,6 +216,7 @@ private:
// Token stream queue.
buffered_queue<std::shared_ptr<Token>, TokenSource> token_queue;
};
+
} // namespace Rust
#endif
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h
index 7483818..784e6d1 100644
--- a/gcc/rust/parse/rust-parse-impl.h
+++ b/gcc/rust/parse/rust-parse-impl.h
@@ -905,6 +905,9 @@ Parser<ManagedTokenSource>::parse_delim_token_tree ()
// parse actual token tree vector - 0 or more
std::vector<std::unique_ptr<AST::TokenTree>> token_trees_in_tree;
+ auto delim_open
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+ token_trees_in_tree.push_back (std::move (delim_open));
// repeat loop until finding the matching delimiter
t = lexer.peek_token ();
@@ -929,6 +932,9 @@ Parser<ManagedTokenSource>::parse_delim_token_tree ()
// lexer.skip_token();
t = lexer.peek_token ();
}
+ auto delim_close
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+ token_trees_in_tree.push_back (std::move (delim_close));
AST::DelimTokenTree token_tree (delim_type, std::move (token_trees_in_tree),
initial_loc);
@@ -1565,6 +1571,9 @@ Parser<ManagedTokenSource>::parse_macro_invocation_semi (
// parse actual token trees
std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
+ auto delim_open
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+ token_trees.push_back (std::move (delim_open));
t = lexer.peek_token ();
// parse token trees until the initial delimiter token is found again
@@ -1587,6 +1596,9 @@ Parser<ManagedTokenSource>::parse_macro_invocation_semi (
t = lexer.peek_token ();
}
+ auto delim_close
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+ token_trees.push_back (std::move (delim_close));
AST::DelimTokenTree delim_tok_tree (delim_type, std::move (token_trees),
tok_tree_locus);
@@ -1605,6 +1617,7 @@ Parser<ManagedTokenSource>::parse_macro_invocation_semi (
if (!skip_token (SEMICOLON))
{
// as this is the end, allow recovery (probably) - may change
+
return std::unique_ptr<AST::MacroInvocationSemi> (
new AST::MacroInvocationSemi (std::move (invoc_data),
std::move (outer_attrs),
@@ -11755,6 +11768,9 @@ Parser<ManagedTokenSource>::parse_path_based_stmt_or_expr (
// parse actual token trees
std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
+ auto delim_open
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3)));
+ token_trees.push_back (std::move (delim_open));
t3 = lexer.peek_token ();
// parse token trees until the initial delimiter token is found again
@@ -11779,6 +11795,10 @@ Parser<ManagedTokenSource>::parse_path_based_stmt_or_expr (
t3 = lexer.peek_token ();
}
+ auto delim_close
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3)));
+ token_trees.push_back (std::move (delim_close));
+
// parse end delimiters
t3 = lexer.peek_token ();
if (token_id_matches_delims (t3->get_id (), type))
@@ -12070,6 +12090,9 @@ Parser<ManagedTokenSource>::parse_macro_invocation_maybe_semi (
// parse actual token trees
std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
+ auto delim_open
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3)));
+ token_trees.push_back (std::move (delim_open));
t3 = lexer.peek_token ();
// parse token trees until the initial delimiter token is found again
@@ -12092,6 +12115,9 @@ Parser<ManagedTokenSource>::parse_macro_invocation_maybe_semi (
t3 = lexer.peek_token ();
}
+ auto delim_close
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3)));
+ token_trees.push_back (std::move (delim_close));
// parse end delimiters
t3 = lexer.peek_token ();
diff --git a/gcc/rust/parse/rust-parse.cc b/gcc/rust/parse/rust-parse.cc
index f2c1301..f995e4b 100644
--- a/gcc/rust/parse/rust-parse.cc
+++ b/gcc/rust/parse/rust-parse.cc
@@ -18,32 +18,6 @@ along with GCC; see the file COPYING3. If not see
#include "rust-linemap.h"
#include "rust-diagnostics.h"
-#if 0
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "target.h"
-#include "tree.h"
-#include "tree-iterator.h"
-#include "input.h"
-#include "diagnostic.h"
-#include "stringpool.h"
-#include "cgraph.h"
-#include "gimplify.h"
-#include "gimple-expr.h"
-#include "convert.h"
-#include "print-tree.h"
-#include "stor-layout.h"
-#include "fold-const.h"
-/* order: config, system, coretypes, target, tree, tree-iterator, input, diagnostic, stringpool,
- * cgraph, gimplify, gimple-expr, convert, print-tree, stor-layout, fold-const */
-// probably don't need all these
-#endif
-// maybe put these back in if compiling no longer works
-
-/* TODO: move non-essential stuff back here from rust-parse-impl.h after
- * confirming that it works */
-
namespace Rust {
std::string
diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h
index acab7ff..5ee7b4e 100644
--- a/gcc/rust/parse/rust-parse.h
+++ b/gcc/rust/parse/rust-parse.h
@@ -86,6 +86,29 @@ struct ParseRestrictions
// TODO: if updated to C++20, ManagedTokenSource would be useful as a concept
template <typename ManagedTokenSource> class Parser
{
+public:
+ bool skip_token (TokenId t);
+
+ std::unique_ptr<AST::Expr>
+ parse_expr (AST::AttrVec outer_attrs = AST::AttrVec (),
+ ParseRestrictions restrictions = ParseRestrictions ());
+
+ std::unique_ptr<AST::LiteralExpr> parse_literal_expr (AST::AttrVec outer_attrs
+ = AST::AttrVec ());
+
+ std::unique_ptr<AST::BlockExpr>
+ parse_block_expr (AST::AttrVec outer_attrs = AST::AttrVec (),
+ Location pratt_parsed_loc = Linemap::unknown_location ());
+
+ std::unique_ptr<AST::Item> parse_item (bool called_from_statement);
+ std::unique_ptr<AST::Pattern> parse_pattern ();
+ std::unique_ptr<AST::Stmt> parse_stmt ();
+ std::unique_ptr<AST::Type> parse_type ();
+ AST::PathInExpression parse_path_in_expression ();
+ std::vector<std::unique_ptr<AST::LifetimeParam> > parse_lifetime_params ();
+ AST::Visibility parse_visibility ();
+ std::unique_ptr<AST::IdentifierPattern> parse_identifier_pattern ();
+
private:
void skip_after_semicolon ();
void skip_after_end ();
@@ -93,7 +116,6 @@ private:
void skip_after_next_block ();
void skip_after_end_attribute ();
- bool skip_token (TokenId t);
const_TokenPtr expect_token (TokenId t);
void unexpected_token (const_TokenPtr t);
bool skip_generics_right_angle ();
@@ -118,7 +140,6 @@ private:
AST::GenericArgs parse_path_generic_args ();
AST::GenericArgsBinding parse_generic_args_binding ();
AST::TypePathFunction parse_type_path_function ();
- AST::PathInExpression parse_path_in_expression ();
AST::PathExprSegment parse_path_expr_segment ();
AST::QualifiedPathInExpression
// When given a pratt_parsed_loc, use it as the location of the
@@ -147,10 +168,8 @@ private:
std::unique_ptr<AST::MacroMatchRepetition> parse_macro_match_repetition ();
// Top-level item-related
- std::unique_ptr<AST::Item> parse_item (bool called_from_statement);
std::unique_ptr<AST::VisItem> parse_vis_item (AST::AttrVec outer_attrs);
std::unique_ptr<AST::MacroItem> parse_macro_item (AST::AttrVec outer_attrs);
- AST::Visibility parse_visibility ();
// VisItem subclass-related
std::unique_ptr<AST::Module> parse_module (AST::Visibility vis,
@@ -169,7 +188,7 @@ private:
template <typename EndTokenPred>
std::vector<std::unique_ptr<AST::GenericParam> >
parse_generic_params (EndTokenPred is_end_token);
- std::vector<std::unique_ptr<AST::LifetimeParam> > parse_lifetime_params ();
+
template <typename EndTokenPred>
std::vector<std::unique_ptr<AST::LifetimeParam> >
parse_lifetime_params (EndTokenPred is_end_token);
@@ -260,9 +279,6 @@ private:
// Expression-related (Pratt parsed)
std::unique_ptr<AST::Expr>
- parse_expr (AST::AttrVec outer_attrs = AST::AttrVec (),
- ParseRestrictions restrictions = ParseRestrictions ());
- std::unique_ptr<AST::Expr>
parse_expr (int right_binding_power,
AST::AttrVec outer_attrs = AST::AttrVec (),
ParseRestrictions restrictions = ParseRestrictions ());
@@ -478,9 +494,6 @@ private:
// When given a pratt_parsed_loc, use it as the location of the
// first token parsed in the expression (the parsing of that first
// token should be skipped).
- std::unique_ptr<AST::BlockExpr>
- parse_block_expr (AST::AttrVec outer_attrs = AST::AttrVec (),
- Location pratt_parsed_loc = Linemap::unknown_location ());
std::unique_ptr<AST::IfExpr>
parse_if_expr (AST::AttrVec outer_attrs = AST::AttrVec (),
Location pratt_parsed_loc = Linemap::unknown_location ());
@@ -518,8 +531,7 @@ private:
std::unique_ptr<AST::ClosureExpr> parse_closure_expr (AST::AttrVec outer_attrs
= AST::AttrVec ());
AST::ClosureParam parse_closure_param ();
- std::unique_ptr<AST::LiteralExpr> parse_literal_expr (AST::AttrVec outer_attrs
- = AST::AttrVec ());
+
// When given a pratt_parsed_loc, use it as the location of the
// first token parsed in the expression (the parsing of that first
// token should be skipped).
@@ -548,7 +560,6 @@ private:
bool will_be_expr_with_block ();
// Type-related
- std::unique_ptr<AST::Type> parse_type ();
std::unique_ptr<AST::TypeNoBounds> parse_type_no_bounds ();
std::unique_ptr<AST::TypeNoBounds> parse_slice_or_array_type ();
std::unique_ptr<AST::RawPointerType> parse_raw_pointer_type ();
@@ -561,7 +572,6 @@ private:
AST::MaybeNamedParam parse_maybe_named_param (AST::AttrVec outer_attrs);
// Statement-related
- std::unique_ptr<AST::Stmt> parse_stmt ();
std::unique_ptr<AST::LetStmt> parse_let_stmt (AST::AttrVec outer_attrs);
std::unique_ptr<AST::ExprStmt> parse_expr_stmt (AST::AttrVec outer_attrs);
std::unique_ptr<AST::ExprStmtWithBlock>
@@ -574,13 +584,11 @@ private:
ExprOrStmt parse_path_based_stmt_or_expr (AST::AttrVec outer_attrs);
// Pattern-related
- std::unique_ptr<AST::Pattern> parse_pattern ();
std::unique_ptr<AST::Pattern> parse_literal_or_range_pattern ();
std::unique_ptr<AST::RangePatternBound> parse_range_pattern_bound ();
std::unique_ptr<AST::ReferencePattern> parse_reference_pattern ();
std::unique_ptr<AST::Pattern> parse_grouped_or_tuple_pattern ();
std::unique_ptr<AST::SlicePattern> parse_slice_pattern ();
- std::unique_ptr<AST::IdentifierPattern> parse_identifier_pattern ();
std::unique_ptr<AST::Pattern> parse_ident_leading_pattern ();
std::unique_ptr<AST::TupleStructItems> parse_tuple_struct_items ();
AST::StructPatternElements parse_struct_pattern_elems ();
@@ -617,6 +625,10 @@ public:
// Get a reference to the list of errors encountered
std::vector<Error> &get_errors () { return error_table; }
+ const ManagedTokenSource &get_token_source () const { return lexer; }
+
+ const_TokenPtr peek_current_token () { return lexer.peek_token (0); }
+
private:
// The token source (usually lexer) associated with the parser.
ManagedTokenSource lexer;
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h
index b7b8646..bb1cbb0 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.h
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.h
@@ -70,6 +70,13 @@ public:
expr->accept_vis (resolver);
};
+ void visit (AST::MacroInvocation &expr) override
+ {
+ AST::ASTFragment &fragment = expr.get_fragment ();
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::TupleIndexExpr &expr) override
{
resolve_expr (expr.get_tuple_expr ().get (), expr.get_node_id ());
diff --git a/gcc/rust/resolve/rust-ast-resolve-implitem.h b/gcc/rust/resolve/rust-ast-resolve-implitem.h
index f17b222..ce7234c 100644
--- a/gcc/rust/resolve/rust-ast-resolve-implitem.h
+++ b/gcc/rust/resolve/rust-ast-resolve-implitem.h
@@ -49,6 +49,13 @@ public:
item->accept_vis (resolver);
}
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::TypeAlias &type) override
{
auto decl
@@ -137,6 +144,13 @@ public:
item->accept_vis (resolver);
};
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::TraitItemFunc &function) override
{
auto decl = ResolveTraitItemFunctionToCanonicalPath::resolve (function);
@@ -240,6 +254,13 @@ public:
item->accept_vis (resolver);
};
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::ExternalFunctionItem &function) override
{
auto decl = CanonicalPath::new_seg (function.get_node_id (),
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
index 5d32c00..48f93e5 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.h
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -45,6 +45,13 @@ public:
item->accept_vis (resolver);
};
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::TraitItemType &type) override
{
auto decl = ResolveTraitItemTypeToCanonicalPath::resolve (type);
@@ -227,6 +234,13 @@ public:
item->accept_vis (resolver);
};
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::TypeAlias &alias) override
{
auto talias = CanonicalPath::new_seg (alias.get_node_id (),
diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h
index 3afed53..7521739 100644
--- a/gcc/rust/resolve/rust-ast-resolve-stmt.h
+++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h
@@ -44,6 +44,14 @@ public:
stmt->accept_vis (resolver);
};
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::ExprStmtWithBlock &stmt) override
{
ResolveExpr::go (stmt.get_expr ().get (), stmt.get_node_id (), prefix,
diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
index 7aba67f..39d6818 100644
--- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h
+++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
@@ -43,6 +43,13 @@ public:
item->accept_vis (resolver);
};
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::Module &module) override
{
auto mod
diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc
index 8aef313..5ac076a 100644
--- a/gcc/rust/resolve/rust-ast-resolve.cc
+++ b/gcc/rust/resolve/rust-ast-resolve.cc
@@ -54,6 +54,7 @@ Resolver::Resolver ()
name_scope (Scope (mappings->get_current_crate ())),
type_scope (Scope (mappings->get_current_crate ())),
label_scope (Scope (mappings->get_current_crate ())),
+ macro_scope (Scope (mappings->get_current_crate ())),
global_type_node_id (UNKNOWN_NODEID), unit_ty_node_id (UNKNOWN_NODEID)
{
generate_builtins ();
@@ -93,6 +94,13 @@ Resolver::push_new_label_rib (Rib *r)
label_ribs[r->get_node_id ()] = r;
}
+void
+Resolver::push_new_macro_rib (Rib *r)
+{
+ rust_assert (label_ribs.find (r->get_node_id ()) == label_ribs.end ());
+ macro_ribs[r->get_node_id ()] = r;
+}
+
bool
Resolver::find_name_rib (NodeId id, Rib **rib)
{
@@ -115,6 +123,17 @@ Resolver::find_type_rib (NodeId id, Rib **rib)
return true;
}
+bool
+Resolver::find_macro_rib (NodeId id, Rib **rib)
+{
+ auto it = macro_ribs.find (id);
+ if (it == macro_ribs.end ())
+ return false;
+
+ *rib = it->second;
+ return true;
+}
+
void
Resolver::insert_builtin_types (Rib *r)
{
@@ -281,6 +300,27 @@ Resolver::lookup_resolved_label (NodeId refId, NodeId *defId)
return true;
}
+void
+Resolver::insert_resolved_macro (NodeId refId, NodeId defId)
+{
+ auto it = resolved_macros.find (refId);
+ rust_assert (it == resolved_macros.end ());
+
+ resolved_labels[refId] = defId;
+ get_label_scope ().append_reference_for_def (refId, defId);
+}
+
+bool
+Resolver::lookup_resolved_macro (NodeId refId, NodeId *defId)
+{
+ auto it = resolved_macros.find (refId);
+ if (it == resolved_macros.end ())
+ return false;
+
+ *defId = it->second;
+ return true;
+}
+
// NameResolution
NameResolution *
diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h
index 199b0f9..2084480 100644
--- a/gcc/rust/resolve/rust-name-resolver.h
+++ b/gcc/rust/resolve/rust-name-resolver.h
@@ -274,10 +274,12 @@ public:
void push_new_name_rib (Rib *r);
void push_new_type_rib (Rib *r);
void push_new_label_rib (Rib *r);
+ void push_new_macro_rib (Rib *r);
bool find_name_rib (NodeId id, Rib **rib);
bool find_type_rib (NodeId id, Rib **rib);
bool find_label_rib (NodeId id, Rib **rib);
+ bool find_macro_rib (NodeId id, Rib **rib);
void insert_new_definition (NodeId id, Definition def);
bool lookup_definition (NodeId id, Definition *def);
@@ -291,10 +293,14 @@ public:
void insert_resolved_label (NodeId refId, NodeId defId);
bool lookup_resolved_label (NodeId refId, NodeId *defId);
+ void insert_resolved_macro (NodeId refId, NodeId defId);
+ bool lookup_resolved_macro (NodeId refId, NodeId *defId);
+
// proxy for scoping
Scope &get_name_scope () { return name_scope; }
Scope &get_type_scope () { return type_scope; }
Scope &get_label_scope () { return label_scope; }
+ Scope &get_macro_scope () { return macro_scope; }
NodeId get_global_type_node_id () { return global_type_node_id; }
@@ -371,6 +377,7 @@ private:
Scope name_scope;
Scope type_scope;
Scope label_scope;
+ Scope macro_scope;
NodeId global_type_node_id;
NodeId unit_ty_node_id;
@@ -379,6 +386,7 @@ private:
std::map<NodeId, Rib *> name_ribs;
std::map<NodeId, Rib *> type_ribs;
std::map<NodeId, Rib *> label_ribs;
+ std::map<NodeId, Rib *> macro_ribs;
// map any Node to its Definition
// ie any name or type usage
@@ -395,6 +403,7 @@ private:
std::map<NodeId, NodeId> resolved_names;
std::map<NodeId, NodeId> resolved_types;
std::map<NodeId, NodeId> resolved_labels;
+ std::map<NodeId, NodeId> resolved_macros;
// map of resolved names mutability flag
std::map<NodeId, bool> decl_mutability;
diff --git a/gcc/rust/typecheck/rust-tycheck-dump.h b/gcc/rust/typecheck/rust-tycheck-dump.h
index 0bcc6c8..53daa42 100644
--- a/gcc/rust/typecheck/rust-tycheck-dump.h
+++ b/gcc/rust/typecheck/rust-tycheck-dump.h
@@ -57,6 +57,12 @@ public:
+= indent () + "union " + type_string (union_decl.get_mappings ()) + "\n";
}
+ void visit (HIR::TupleStruct &struct_decl) override
+ {
+ dump += indent () + "struct" + type_string (struct_decl.get_mappings ())
+ + "\n";
+ }
+
void visit (HIR::ImplBlock &impl_block) override
{
dump += indent () + "impl "
diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc
index 04db333..1348e29 100644
--- a/gcc/rust/util/rust-hir-map.cc
+++ b/gcc/rust/util/rust-hir-map.cc
@@ -738,5 +738,25 @@ Mappings::iterate_trait_items (
}
}
+void
+Mappings::insert_macro_def (AST::MacroRulesDefinition *macro)
+{
+ auto it = macroMappings.find (macro->get_node_id ());
+ rust_assert (it == macroMappings.end ());
+
+ macroMappings[macro->get_node_id ()] = macro;
+}
+
+bool
+Mappings::lookup_macro_def (NodeId id, AST::MacroRulesDefinition **def)
+{
+ auto it = macroMappings.find (id);
+ if (it == macroMappings.end ())
+ return false;
+
+ *def = it->second;
+ return true;
+}
+
} // namespace Analysis
} // namespace Rust
diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h
index 8781629..799351b 100644
--- a/gcc/rust/util/rust-hir-map.h
+++ b/gcc/rust/util/rust-hir-map.h
@@ -559,6 +559,10 @@ public:
return true;
}
+ void insert_macro_def (AST::MacroRulesDefinition *macro);
+
+ bool lookup_macro_def (NodeId id, AST::MacroRulesDefinition **def);
+
private:
Mappings ();
@@ -612,6 +616,9 @@ private:
// all hirid nodes
std::map<CrateNum, std::set<HirId>> hirNodesWithinCrate;
+ // macros
+ std::map<NodeId, AST::MacroRulesDefinition *> macroMappings;
+
// crate names
std::map<CrateNum, std::string> crate_names;
};
diff --git a/gcc/testsuite/rust/execute/torture/macros1.rs b/gcc/testsuite/rust/execute/torture/macros1.rs
new file mode 100644
index 0000000..652d2d8
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/macros1.rs
@@ -0,0 +1,13 @@
+macro_rules! add {
+ ($a:expr,$b:expr) => {
+ $a + $b
+ };
+}
+
+fn test() -> i32 {
+ add!(1 + 2, 3)
+}
+
+fn main() -> i32 {
+ test() - 6
+}
diff --git a/gcc/testsuite/rust/execute/torture/macros2.rs b/gcc/testsuite/rust/execute/torture/macros2.rs
new file mode 100644
index 0000000..0116bd1
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/macros2.rs
@@ -0,0 +1,40 @@
+// { dg-output "arg\narg\narg\n" }
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+fn f() {
+ unsafe {
+ let r_s = "arg\n\0";
+ let s_p = r_s as *const str;
+ let c_p = s_p as *const i8;
+
+ printf(c_p);
+ }
+}
+
+macro_rules! kw0 {
+ (keyword) => {
+ f()
+ };
+}
+
+macro_rules! kw1 {
+ (fn) => {
+ f()
+ };
+}
+
+macro_rules! kw2 {
+ (kw0 kw1 kw3) => {
+ f()
+ };
+}
+
+fn main() -> i32 {
+ kw0!(keyword);
+ kw1!(fn);
+ kw2!(kw0 kw1 kw3);
+
+ 0
+}
diff --git a/gcc/testsuite/rust/execute/torture/macros3.rs b/gcc/testsuite/rust/execute/torture/macros3.rs
new file mode 100644
index 0000000..c1f5a53
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/macros3.rs
@@ -0,0 +1,61 @@
+// { dg-output "invok\ninvok\ninvok\ninvok\ninvok\n" }
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+fn f() {
+ unsafe {
+ let r_s = "invok\n\0";
+ let s_p = r_s as *const str;
+ let c_p = s_p as *const i8;
+
+ printf(c_p);
+ }
+}
+
+macro_rules! invocation0 {
+ (valid) => {
+ f()
+ };
+ () => {};
+}
+
+macro_rules! invocation1 {
+ (valid) => {};
+ () => {
+ f()
+ };
+}
+
+macro_rules! invocation2 {
+ (valid) => {
+ f()
+ };
+ (invalid) => {};
+}
+
+macro_rules! invocation3 {
+ (this is a valid invocation) => {
+ f()
+ };
+ (not this one) => {};
+}
+
+macro_rules! invocation4 {
+ (fn f() {}) => {
+ f()
+ };
+ (not a keyword) => {};
+}
+
+fn main() -> i32 {
+ invocation0!(valid);
+ invocation1!();
+ invocation2!(valid);
+ invocation3!(this is a valid invocation);
+ invocation4!(
+ fn f() {}
+ );
+
+ 0
+}
diff --git a/gcc/testsuite/rust/execute/torture/macros4.rs b/gcc/testsuite/rust/execute/torture/macros4.rs
new file mode 100644
index 0000000..3303bfa
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/macros4.rs
@@ -0,0 +1,15 @@
+macro_rules! add {
+ ($a:expr,$b:expr) => {
+ $a + $b
+ };
+ ($a:expr) => {
+ $a
+ };
+}
+
+fn main() -> i32 {
+ let mut x = add!(1);
+ x += add!(2, 3);
+
+ x - 6
+}
diff --git a/gcc/testsuite/rust/execute/torture/macros5.rs b/gcc/testsuite/rust/execute/torture/macros5.rs
new file mode 100644
index 0000000..8226654
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/macros5.rs
@@ -0,0 +1,13 @@
+macro_rules! add {
+ ($a:expr,$b:expr) => {{
+ $a + $b
+ }};
+}
+
+fn test() -> i32 {
+ add!(1, 2)
+}
+
+fn main() -> i32 {
+ test() - 3
+}
diff --git a/gcc/testsuite/rust/execute/torture/macros6.rs b/gcc/testsuite/rust/execute/torture/macros6.rs
new file mode 100644
index 0000000..652a765
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/macros6.rs
@@ -0,0 +1,12 @@
+macro_rules! Test {
+ ($a:ident, $b:ty) => {
+ struct $a($b);
+ };
+}
+
+Test!(Foo, i32);
+
+fn main() -> i32 {
+ let a = Foo(123);
+ a.0 - 123
+}
diff --git a/gcc/testsuite/rust/execute/xfail/macro2.rs b/gcc/testsuite/rust/execute/xfail/macro2.rs
deleted file mode 100644
index 49bd6a8..0000000
--- a/gcc/testsuite/rust/execute/xfail/macro2.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// { dg-output "arg\narg\n" }
-extern "C" {
- fn printf(s: *const i8, ...);
-}
-
-fn f() {
- let r_s = "arg\n\0";
- let s_p = r_s as *const str;
- let c_p = s_p as *const i8;
-
- printf(c_p);
-}
-
-macro_rules! kw0 {
- (keyword) => { f() };
-}
-
-macro_rules! kw1 {
- (fn) => { f() };
-}
-
-macro_rules! kw2 {
- (kw0 kw1 kw3) => { f() };
-}
-
-fn main() {
- kw0!(keyword);
- kw1!(fn);
- kw2!(kw0 kw1 kw3);
-}
diff --git a/gcc/testsuite/rust/execute/xfail/macro3.rs b/gcc/testsuite/rust/execute/xfail/macro3.rs
deleted file mode 100644
index 0d99d716..0000000
--- a/gcc/testsuite/rust/execute/xfail/macro3.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-// { dg-output "invok\ninvok\ninvok\ninvok\ninvok\n" }
-extern "C" {
- fn printf(s: *const i8, ...);
-}
-
-fn f() {
- let r_s = "invok\n\0";
- let s_p = r_s as *const str;
- let c_p = s_p as *const i8;
-
- printf(c_p);
-}
-
-macro_rules! invocation0 {
- (valid) => { f() };
- () => { };
-}
-
-macro_rules! invocation1 {
- (valid) => { };
- () => { f() };
-}
-
-macro_rules! invocation2 {
- (valid) => { f() };
- (invalid) => { };
-}
-
-macro_rules! invocation3 {
- (this is a valid invocation) => { f() };
- (not this one) => { };
-}
-
-macro_rules! invocation4 {
- (fn f() {}) => { f() };
- (not a keyword) => { };
-}
-
-fn main() {
- invocation0!(valid);
- invocation1!();
- invocation2!(valid);
- invocation3!(this is a valid invocation);
- invocation4!(fn f() {});
-}