aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
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() {});
-}