Skip to content

Commit 5c38744

Browse files
committed
expand: Add handling for macro expansion in pattern context
gcc/rust/ChangeLog: * ast/rust-ast-fragment.cc (Fragment::is_pattern_fragment): New function. (Fragment::take_pattern_fragment): Likewise. (Fragment::assert_single_fragment): Likewise. * ast/rust-ast-fragment.h: Declare them. * ast/rust-ast.cc (SingleASTNode::SingleASTNode): Add new constructor for pattern single AST nodes. (SingleASTNode::operator=): Handle patterns. (SingleASTNode::accept_vis): Likewise. (SingleASTNode::is_error): Likewise. (SingleASTNode::as_string): Likewise. * ast/rust-ast.h: Add get_pattern_ptr() functions. * ast/rust-expr.h: Likewise. * ast/rust-item.h: Likewise. * ast/rust-pattern.h: Likewise. * ast/rust-stmt.h: Likewise. * expand/rust-expand-visitor.cc (derive_item): Use new API enum values. (expand_item_attribute): Likewise. (expand_stmt_attribute): Likewise. (ExpandVisitor::maybe_expand_pattern): New function. (ExpandVisitor::expand_closure_params): Handle patterns. (ExpandVisitor::visit): Add new visitors for patterns and missed exprs. * expand/rust-expand-visitor.h: Declare them. * expand/rust-macro-expand.cc (transcribe_pattern): New function. (transcribe_context): Call it. * expand/rust-macro-expand.h (struct MacroExpander): New Context type. gcc/testsuite/ChangeLog: * rust/compile/issue-3726.rs: New test. * rust/compile/issue-3898.rs: New test.
1 parent 6e46145 commit 5c38744

14 files changed

+344
-17
lines changed

gcc/rust/ast/rust-ast-fragment.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ Fragment::is_type_fragment () const
116116
return is_single_fragment_of_kind (SingleASTNode::Kind::Type);
117117
}
118118

119+
bool
120+
Fragment::is_pattern_fragment () const
121+
{
122+
return is_single_fragment_of_kind (SingleASTNode::Kind::Pattern);
123+
}
124+
119125
std::unique_ptr<Expr>
120126
Fragment::take_expression_fragment ()
121127
{
@@ -130,6 +136,13 @@ Fragment::take_type_fragment ()
130136
return nodes[0].take_type ();
131137
}
132138

139+
std::unique_ptr<Pattern>
140+
Fragment::take_pattern_fragment ()
141+
{
142+
assert_single_fragment (SingleASTNode::Kind::Pattern);
143+
return nodes[0].take_pattern ();
144+
}
145+
133146
void
134147
Fragment::accept_vis (ASTVisitor &vis)
135148
{
@@ -159,6 +172,7 @@ Fragment::assert_single_fragment (SingleASTNode::Kind expected) const
159172
{SingleASTNode::Kind::Expr, "expr"},
160173
{SingleASTNode::Kind::Stmt, "stmt"},
161174
{SingleASTNode::Kind::Extern, "extern"},
175+
{SingleASTNode::Kind::Pattern, "pattern"},
162176
};
163177

164178
auto actual = nodes[0].get_kind ();

gcc/rust/ast/rust-ast-fragment.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,11 @@ class Fragment
8686

8787
bool is_expression_fragment () const;
8888
bool is_type_fragment () const;
89+
bool is_pattern_fragment () const;
8990

9091
std::unique_ptr<Expr> take_expression_fragment ();
9192
std::unique_ptr<Type> take_type_fragment ();
93+
std::unique_ptr<Pattern> take_pattern_fragment ();
9294

9395
void accept_vis (ASTVisitor &vis);
9496

gcc/rust/ast/rust-ast.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ SingleASTNode::SingleASTNode (SingleASTNode const &other)
7171
case Kind::Type:
7272
type = other.type->clone_type ();
7373
break;
74+
75+
case Kind::Pattern:
76+
pattern = other.pattern->clone_pattern ();
77+
break;
7478
}
7579
}
7680

@@ -103,6 +107,10 @@ SingleASTNode::operator= (SingleASTNode const &other)
103107
case Kind::Type:
104108
type = other.type->clone_type ();
105109
break;
110+
111+
case Kind::Pattern:
112+
pattern = other.pattern->clone_pattern ();
113+
break;
106114
}
107115
return *this;
108116
}
@@ -135,6 +143,10 @@ SingleASTNode::accept_vis (ASTVisitor &vis)
135143
case Kind::Type:
136144
type->accept_vis (vis);
137145
break;
146+
147+
case Kind::Pattern:
148+
pattern->accept_vis (vis);
149+
break;
138150
}
139151
}
140152

@@ -155,6 +167,8 @@ SingleASTNode::is_error ()
155167
return assoc_item == nullptr;
156168
case Kind::Type:
157169
return type == nullptr;
170+
case Kind::Pattern:
171+
return pattern == nullptr;
158172
}
159173

160174
rust_unreachable ();
@@ -178,6 +192,8 @@ SingleASTNode::as_string () const
178192
return "Associated Item: " + assoc_item->as_string ();
179193
case Kind::Type:
180194
return "Type: " + type->as_string ();
195+
case Kind::Pattern:
196+
return "Pattern: " + pattern->as_string ();
181197
}
182198

183199
rust_unreachable ();

gcc/rust/ast/rust-ast.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,6 +1970,7 @@ class SingleASTNode : public Visitable
19701970
Extern,
19711971
Assoc,
19721972
Type,
1973+
Pattern,
19731974
};
19741975

19751976
private:
@@ -1982,6 +1983,7 @@ class SingleASTNode : public Visitable
19821983
std::unique_ptr<ExternalItem> external_item;
19831984
std::unique_ptr<AssociatedItem> assoc_item;
19841985
std::unique_ptr<Type> type;
1986+
std::unique_ptr<Pattern> pattern;
19851987

19861988
public:
19871989
SingleASTNode (std::unique_ptr<Expr> expr)
@@ -2008,6 +2010,10 @@ class SingleASTNode : public Visitable
20082010
: kind (Kind::Type), type (std::move (type))
20092011
{}
20102012

2013+
SingleASTNode (std::unique_ptr<Pattern> pattern)
2014+
: kind (Kind::Pattern), pattern (std::move (pattern))
2015+
{}
2016+
20112017
SingleASTNode (SingleASTNode const &other);
20122018

20132019
SingleASTNode operator= (SingleASTNode const &other);
@@ -2076,6 +2082,12 @@ class SingleASTNode : public Visitable
20762082
return std::move (type);
20772083
}
20782084

2085+
std::unique_ptr<Pattern> take_pattern ()
2086+
{
2087+
rust_assert (!is_error ());
2088+
return std::move (pattern);
2089+
}
2090+
20792091
void accept_vis (ASTVisitor &vis) override;
20802092

20812093
bool is_error ();

gcc/rust/ast/rust-expr.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2492,6 +2492,12 @@ struct ClosureParam
24922492
return *pattern;
24932493
}
24942494

2495+
std::unique_ptr<Pattern> &get_pattern_ptr ()
2496+
{
2497+
rust_assert (pattern != nullptr);
2498+
return pattern;
2499+
}
2500+
24952501
Type &get_type ()
24962502
{
24972503
rust_assert (has_type_given ());

gcc/rust/ast/rust-item.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,12 @@ class VariadicParam : public Param
631631
return *param_name;
632632
}
633633

634+
std::unique_ptr<Pattern> &get_pattern_ptr ()
635+
{
636+
rust_assert (param_name != nullptr);
637+
return param_name;
638+
}
639+
634640
const Pattern &get_pattern () const
635641
{
636642
rust_assert (param_name != nullptr);
@@ -714,6 +720,12 @@ class FunctionParam : public Param
714720
return *param_name;
715721
}
716722

723+
std::unique_ptr<Pattern> &get_pattern_ptr ()
724+
{
725+
rust_assert (param_name != nullptr);
726+
return param_name;
727+
}
728+
717729
bool has_name () const { return param_name != nullptr; }
718730

719731
// TODO: is this better? Or is a "vis_block" better?

gcc/rust/ast/rust-pattern.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,6 +1509,12 @@ class GroupedPattern : public Pattern
15091509
return *pattern_in_parens;
15101510
}
15111511

1512+
std::unique_ptr<Pattern> &get_pattern_in_parens_ptr ()
1513+
{
1514+
rust_assert (pattern_in_parens != nullptr);
1515+
return pattern_in_parens;
1516+
}
1517+
15121518
NodeId get_node_id () const override { return node_id; }
15131519

15141520
Pattern::Kind get_pattern_kind () override { return Pattern::Kind::Grouped; }

gcc/rust/ast/rust-stmt.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,12 @@ class LetStmt : public Stmt
201201
return *variables_pattern;
202202
}
203203

204+
std::unique_ptr<Pattern> &get_pattern_ptr ()
205+
{
206+
rust_assert (variables_pattern != nullptr);
207+
return variables_pattern;
208+
}
209+
204210
Type &get_type ()
205211
{
206212
rust_assert (has_type ());

gcc/rust/expand/rust-expand-visitor.cc

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "rust-expand-visitor.h"
2020
#include "rust-ast-fragment.h"
21+
#include "rust-item.h"
2122
#include "rust-proc-macro.h"
2223
#include "rust-attributes.h"
2324
#include "rust-ast.h"
@@ -62,7 +63,7 @@ derive_item (AST::Item &item, AST::SimplePath &to_derive,
6263
{
6364
switch (node.get_kind ())
6465
{
65-
case AST::SingleASTNode::ITEM:
66+
case AST::SingleASTNode::Kind::Item:
6667
result.push_back (node.take_item ());
6768
break;
6869
default:
@@ -85,7 +86,7 @@ expand_item_attribute (AST::Item &item, AST::SimplePath &name,
8586
{
8687
switch (node.get_kind ())
8788
{
88-
case AST::SingleASTNode::ITEM:
89+
case AST::SingleASTNode::Kind::Item:
8990
result.push_back (node.take_item ());
9091
break;
9192
default:
@@ -114,7 +115,7 @@ expand_stmt_attribute (T &statement, AST::SimplePath &attribute,
114115
{
115116
switch (node.get_kind ())
116117
{
117-
case AST::SingleASTNode::STMT:
118+
case AST::SingleASTNode::Kind::Stmt:
118119
result.push_back (node.take_stmt ());
119120
break;
120121
default:
@@ -380,6 +381,23 @@ ExpandVisitor::maybe_expand_type (std::unique_ptr<AST::TypeNoBounds> &type)
380381
final_fragment.take_type_fragment (), BUILTINS_LOCATION);
381382
}
382383

384+
void
385+
ExpandVisitor::maybe_expand_pattern (std::unique_ptr<AST::Pattern> &pattern)
386+
{
387+
NodeId old_expect = pattern->get_node_id ();
388+
std::swap (macro_invoc_expect_id, old_expect);
389+
390+
expander.push_context (MacroExpander::ContextType::PATTERN);
391+
pattern->accept_vis (*this);
392+
expander.pop_context ();
393+
394+
std::swap (macro_invoc_expect_id, old_expect);
395+
396+
auto final_fragment = expander.take_expanded_fragment ();
397+
if (final_fragment.should_expand () && final_fragment.is_pattern_fragment ())
398+
pattern = final_fragment.take_pattern_fragment ();
399+
}
400+
383401
// FIXME: Can this be refactored into a `scoped` method? Which takes a
384402
// ContextType as parameter and a lambda? And maybe just an std::vector<T>&?
385403
void
@@ -452,6 +470,8 @@ ExpandVisitor::expand_closure_params (std::vector<AST::ClosureParam> &params)
452470
{
453471
for (auto &param : params)
454472
{
473+
maybe_expand_pattern (param.get_pattern_ptr ());
474+
455475
if (param.has_type_given ())
456476
maybe_expand_type (param.get_type_ptr ());
457477
}
@@ -729,7 +749,7 @@ ExpandVisitor::visit (AST::MatchExpr &expr)
729749
auto &arm = match_case.get_arm ();
730750

731751
for (auto &pattern : arm.get_patterns ())
732-
visit (pattern);
752+
maybe_expand_pattern (pattern);
733753

734754
if (arm.has_match_arm_guard ())
735755
maybe_expand_expr (arm.get_guard_expr_ptr ());
@@ -738,6 +758,13 @@ ExpandVisitor::visit (AST::MatchExpr &expr)
738758
}
739759
}
740760

761+
void
762+
ExpandVisitor::visit (AST::TupleExpr &expr)
763+
{
764+
for (auto &sub : expr.get_tuple_elems ())
765+
maybe_expand_expr (sub);
766+
}
767+
741768
void
742769
ExpandVisitor::visit (AST::TypeParam &param)
743770
{
@@ -1013,13 +1040,70 @@ ExpandVisitor::visit (AST::StructPatternFieldIdent &field)
10131040
void
10141041
ExpandVisitor::visit (AST::GroupedPattern &pattern)
10151042
{
1016-
visit (pattern.get_pattern_in_parens ());
1043+
maybe_expand_pattern (pattern.get_pattern_in_parens_ptr ());
1044+
}
1045+
1046+
void
1047+
ExpandVisitor::visit (AST::SlicePatternItemsNoRest &items)
1048+
{
1049+
for (auto &sub : items.get_patterns ())
1050+
maybe_expand_pattern (sub);
1051+
}
1052+
1053+
void
1054+
ExpandVisitor::visit (AST::SlicePatternItemsHasRest &items)
1055+
{
1056+
for (auto &sub : items.get_lower_patterns ())
1057+
maybe_expand_pattern (sub);
1058+
for (auto &sub : items.get_upper_patterns ())
1059+
maybe_expand_pattern (sub);
1060+
}
1061+
1062+
void
1063+
ExpandVisitor::visit (AST::AltPattern &pattern)
1064+
{
1065+
for (auto &alt : pattern.get_alts ())
1066+
maybe_expand_pattern (alt);
1067+
}
1068+
1069+
void
1070+
ExpandVisitor::visit (AST::TupleStructItemsNoRange &tuple_items)
1071+
{
1072+
for (auto &sub : tuple_items.get_patterns ())
1073+
maybe_expand_pattern (sub);
1074+
}
1075+
1076+
void
1077+
ExpandVisitor::visit (AST::TupleStructItemsRange &tuple_items)
1078+
{
1079+
for (auto &sub : tuple_items.get_lower_patterns ())
1080+
maybe_expand_pattern (sub);
1081+
1082+
for (auto &sub : tuple_items.get_upper_patterns ())
1083+
maybe_expand_pattern (sub);
1084+
}
1085+
1086+
void
1087+
ExpandVisitor::visit (AST::TuplePatternItemsMultiple &tuple_items)
1088+
{
1089+
for (auto &sub : tuple_items.get_patterns ())
1090+
maybe_expand_pattern (sub);
1091+
}
1092+
1093+
void
1094+
ExpandVisitor::visit (AST::TuplePatternItemsRanged &tuple_items)
1095+
{
1096+
for (auto &sub : tuple_items.get_lower_patterns ())
1097+
maybe_expand_pattern (sub);
1098+
1099+
for (auto &sub : tuple_items.get_upper_patterns ())
1100+
maybe_expand_pattern (sub);
10171101
}
10181102

10191103
void
10201104
ExpandVisitor::visit (AST::LetStmt &stmt)
10211105
{
1022-
visit (stmt.get_pattern ());
1106+
maybe_expand_pattern (stmt.get_pattern_ptr ());
10231107

10241108
if (stmt.has_type ())
10251109
maybe_expand_type (stmt.get_type_ptr ());
@@ -1049,9 +1133,17 @@ ExpandVisitor::visit (AST::BareFunctionType &type)
10491133
void
10501134
ExpandVisitor::visit (AST::FunctionParam &param)
10511135
{
1136+
maybe_expand_pattern (param.get_pattern_ptr ());
10521137
maybe_expand_type (param.get_type_ptr ());
10531138
}
10541139

1140+
void
1141+
ExpandVisitor::visit (AST::VariadicParam &param)
1142+
{
1143+
if (param.has_pattern ())
1144+
maybe_expand_pattern (param.get_pattern_ptr ());
1145+
}
1146+
10551147
void
10561148
ExpandVisitor::visit (AST::SelfParam &param)
10571149
{

0 commit comments

Comments
 (0)