aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/ast/rust-ast.h2
-rw-r--r--gcc/rust/ast/rust-macro.h9
-rw-r--r--gcc/rust/ast/rust-stmt.h5
-rw-r--r--gcc/rust/expand/rust-expand-visitor.cc13
-rw-r--r--gcc/rust/expand/rust-macro-expand.cc20
-rw-r--r--gcc/rust/expand/rust-macro-expand.h3
-rw-r--r--gcc/rust/parse/rust-parse-impl.h842
-rw-r--r--gcc/rust/parse/rust-parse.h19
-rw-r--r--gcc/testsuite/rust/compile/braced_macro_arm.rs19
-rw-r--r--gcc/testsuite/rust/compile/braced_macro_statements1.rs15
-rw-r--r--gcc/testsuite/rust/compile/braced_macro_statements2.rs15
-rw-r--r--gcc/testsuite/rust/compile/braced_macro_statements3.rs11
-rw-r--r--gcc/testsuite/rust/compile/issue-2225.rs2
13 files changed, 353 insertions, 622 deletions
diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h
index a9b31e0..1e9b5f3 100644
--- a/gcc/rust/ast/rust-ast.h
+++ b/gcc/rust/ast/rust-ast.h
@@ -988,8 +988,6 @@ public:
virtual std::vector<Attribute> &get_outer_attrs () = 0;
- virtual Expr *to_stmt () const { return clone_expr_impl (); }
-
// TODO: think of less hacky way to implement this kind of thing
// Sets outer attributes.
virtual void set_outer_attrs (std::vector<Attribute>) = 0;
diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h
index 4e24144..075ae63 100644
--- a/gcc/rust/ast/rust-macro.h
+++ b/gcc/rust/ast/rust-macro.h
@@ -811,15 +811,6 @@ protected:
{
return clone_macro_invocation_impl ();
}
-
- Expr *to_stmt () const override
-
- {
- auto new_impl = clone_macro_invocation_impl ();
- new_impl->is_semi_coloned = true;
-
- return new_impl;
- }
};
// more generic meta item path-only form
diff --git a/gcc/rust/ast/rust-stmt.h b/gcc/rust/ast/rust-stmt.h
index 6e2113a..d2cace6 100644
--- a/gcc/rust/ast/rust-stmt.h
+++ b/gcc/rust/ast/rust-stmt.h
@@ -201,8 +201,9 @@ public:
std::vector<LetStmt *> locals;
- ExprStmt (std::unique_ptr<Expr> expr, Location locus, bool semicolon_followed)
- : expr (expr->to_stmt ()), locus (locus),
+ ExprStmt (std::unique_ptr<Expr> &&expr, Location locus,
+ bool semicolon_followed)
+ : expr (std::move (expr)), locus (locus),
semicolon_followed (semicolon_followed)
{}
diff --git a/gcc/rust/expand/rust-expand-visitor.cc b/gcc/rust/expand/rust-expand-visitor.cc
index 3601287..9183a63 100644
--- a/gcc/rust/expand/rust-expand-visitor.cc
+++ b/gcc/rust/expand/rust-expand-visitor.cc
@@ -232,7 +232,7 @@ void
ExpandVisitor::expand_inner_stmts (
std::vector<std::unique_ptr<AST::Stmt>> &stmts)
{
- expander.push_context (MacroExpander::ContextType::BLOCK);
+ expander.push_context (MacroExpander::ContextType::STMT);
for (auto it = stmts.begin (); it != stmts.end (); it++)
{
@@ -272,10 +272,9 @@ ExpandVisitor::expand_inner_stmts (
void
ExpandVisitor::maybe_expand_expr (std::unique_ptr<AST::Expr> &expr)
{
- // FIXME: ARTHUR: Why isn't there a ContextType::EXPR? We can only
- // reach `parse_expr` once in MacroExpander::transcribe_rule(), but it
- // would make things clearer wouldn't it?
+ expander.push_context (MacroExpander::ContextType::EXPR);
expr->accept_vis (*this);
+ expander.pop_context ();
auto final_fragment = expander.take_expanded_fragment ();
if (final_fragment.should_expand ()
@@ -732,12 +731,8 @@ ExpandVisitor::visit (AST::BlockExpr &expr)
{
expand_inner_stmts (expr.get_statements ());
- expander.push_context (MacroExpander::ContextType::BLOCK);
-
if (expr.has_tail_expr ())
maybe_expand_expr (expr.get_tail_expr ());
-
- expander.pop_context ();
}
void
@@ -1438,7 +1433,7 @@ ExpandVisitor::visit (AST::LetStmt &stmt)
void
ExpandVisitor::visit (AST::ExprStmt &stmt)
{
- visit (stmt.get_expr ());
+ maybe_expand_expr (stmt.get_expr ());
}
void
diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc
index a5a11cb..bb981a3 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -895,16 +895,6 @@ transcribe_type (Parser<MacroInvocLexer> &parser)
}
static AST::Fragment
-transcribe_on_delimiter (Parser<MacroInvocLexer> &parser, bool semicolon,
- AST::DelimType delimiter, TokenId last_token_id)
-{
- if (semicolon || delimiter == AST::DelimType::CURLY)
- return transcribe_many_stmts (parser, last_token_id);
- else
- return transcribe_expression (parser);
-} // namespace Rust
-
-static AST::Fragment
transcribe_context (MacroExpander::ContextType ctx,
Parser<MacroInvocLexer> &parser, bool semicolon,
AST::DelimType delimiter, TokenId last_token_id)
@@ -945,9 +935,12 @@ transcribe_context (MacroExpander::ContextType ctx,
case MacroExpander::ContextType::TYPE:
return transcribe_type (parser);
break;
+ case MacroExpander::ContextType::STMT:
+ return transcribe_many_stmts (parser, last_token_id, semicolon);
+ case MacroExpander::ContextType::EXPR:
+ return transcribe_expression (parser);
default:
- return transcribe_on_delimiter (parser, semicolon, delimiter,
- last_token_id);
+ gcc_unreachable ();
}
}
@@ -1111,7 +1104,7 @@ MacroExpander::parse_proc_macro_output (ProcMacro::TokenStream ts)
nodes.push_back ({std::move (result)});
}
break;
- case ContextType::BLOCK:
+ case ContextType::STMT:
while (lex.peek_token ()->get_id () != END_OF_FILE)
{
auto result = parser.parse_stmt ();
@@ -1125,6 +1118,7 @@ MacroExpander::parse_proc_macro_output (ProcMacro::TokenStream ts)
case ContextType::TRAIT_IMPL:
case ContextType::EXTERN:
case ContextType::TYPE:
+ case ContextType::EXPR:
default:
gcc_unreachable ();
}
diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h
index b495513..a03de5a 100644
--- a/gcc/rust/expand/rust-macro-expand.h
+++ b/gcc/rust/expand/rust-macro-expand.h
@@ -221,7 +221,8 @@ struct MacroExpander
enum class ContextType
{
ITEM,
- BLOCK,
+ STMT,
+ EXPR,
EXTERN,
TYPE,
TRAIT,
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h
index c9dbee2..627b4cc 100644
--- a/gcc/rust/parse/rust-parse-impl.h
+++ b/gcc/rust/parse/rust-parse-impl.h
@@ -6266,19 +6266,12 @@ Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions)
return parse_vis_item (std::move (outer_attrs));
// or should this go straight to parsing union?
}
- else if (t->get_str () == "macro_rules")
+ else if (t->get_str () == "macro_rules"
+ && lexer.peek_token (1)->get_id () == EXCLAM)
{
// macro_rules! macro item
return parse_macro_rules_def (std::move (outer_attrs));
}
- else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
- || lexer.peek_token (1)->get_id () == EXCLAM)
- {
- // FIXME: ensure doesn't take any expressions by mistake
- /* path (probably) or macro invocation, so probably a macro
- * invocation semi */
- return parse_macro_invocation_semi (std::move (outer_attrs));
- }
gcc_fallthrough ();
// TODO: find out how to disable gcc "implicit fallthrough" warning
default:
@@ -7269,19 +7262,77 @@ Parser<ManagedTokenSource>::parse_method ()
AST::Visibility::create_error (), AST::AttrVec (), locus);
}
-/* Parses an expression statement. */
+/* Parses an expression or macro statement. */
template <typename ManagedTokenSource>
-std::unique_ptr<AST::ExprStmt>
+std::unique_ptr<AST::Stmt>
Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
ParseRestrictions restrictions)
{
Location locus = lexer.peek_token ()->get_locus ();
- restrictions.expr_can_be_stmt = true;
+ std::unique_ptr<AST::Expr> expr;
+
+ switch (lexer.peek_token ()->get_id ())
+ {
+ case IDENTIFIER:
+ case CRATE:
+ case SUPER:
+ case SELF:
+ case SELF_ALIAS:
+ case DOLLAR_SIGN:
+ case SCOPE_RESOLUTION: {
+ AST::PathInExpression path = parse_path_in_expression ();
+ std::unique_ptr<AST::Expr> null_denotation;
+
+ if (lexer.peek_token ()->get_id () == EXCLAM)
+ {
+ // Bind a reference to avoid -Wredundant-move on post-P1825R0
+ // compilers. Change to non-reference type and remove the moves
+ // below once C++20 is required to build gcc.
+ std::unique_ptr<AST::MacroInvocation> &&invoc
+ = parse_macro_invocation_partial (std::move (path),
+ std::move (outer_attrs));
+
+ if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
+ {
+ invoc->add_semicolon ();
+ // Macro invocation with semicolon.
+ return std::move (invoc);
+ }
+
+ TokenId after_macro = lexer.peek_token ()->get_id ();
+
+ if (restrictions.allow_close_after_expr_stmt
+ && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY
+ || after_macro == RIGHT_SQUARE))
+ return std::move (invoc);
+
+ if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
+ == AST::CURLY
+ && after_macro != DOT && after_macro != QUESTION_MARK)
+ {
+ rust_debug ("braced macro statement");
+ return std::move (invoc);
+ }
+
+ null_denotation = std::move (invoc);
+ }
+ else
+ {
+ null_denotation
+ = null_denotation_path (std::move (path), {}, restrictions);
+ }
+
+ expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
+ std::move (outer_attrs), restrictions);
+ break;
+ }
+ default:
+ restrictions.expr_can_be_stmt = true;
+ expr = parse_expr (std::move (outer_attrs), restrictions);
+ break;
+ }
- // attempt to parse via parse_expr_without_block - seems to work
- std::unique_ptr<AST::Expr> expr
- = parse_expr (std::move (outer_attrs), restrictions);
if (expr == nullptr)
{
// expr is required, error
@@ -7301,7 +7352,7 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
{
has_semi = true;
}
- else if (!expr->is_expr_without_block ())
+ else if (expr->is_expr_without_block ())
{
if (restrictions.allow_close_after_expr_stmt)
{
@@ -8466,7 +8517,6 @@ Parser<ManagedTokenSource>::parse_match_expr (AST::AttrVec outer_attrs,
ParseRestrictions restrictions;
restrictions.expr_can_be_stmt = true;
- restrictions.consume_semi = false;
std::unique_ptr<AST::Expr> expr = parse_expr ({}, restrictions);
@@ -11562,6 +11612,7 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr ()
AST::AttrVec outer_attrs = parse_outer_attributes ();
ParseRestrictions restrictions;
restrictions.expr_can_be_stmt = true;
+ std::unique_ptr<AST::Expr> expr;
// parsing this will be annoying because of the many different possibilities
/* best may be just to copy paste in parse_item switch, and failing that try
@@ -11614,6 +11665,7 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr ()
{
case LEFT_CURLY: {
// unsafe block: parse as expression
+ expr = parse_expr (std::move (outer_attrs), restrictions);
break;
}
case AUTO:
@@ -11649,8 +11701,6 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr ()
}
/* FIXME: this is either a macro invocation or macro invocation semi.
* start parsing to determine which one it is. */
- // FIXME: or this is another path-based thing - struct/enum or path
- // itself return parse_path_based_stmt_or_expr(std::move(outer_attrs));
// FIXME: old code there
// crappy hack to do union "keyword"
@@ -11663,27 +11713,68 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr ()
return ExprOrStmt (std::move (item));
// or should this go straight to parsing union?
}
- else if (t->get_str () == "macro_rules")
+ else if (t->get_str () == "macro_rules"
+ && lexer.peek_token (1)->get_id () == EXCLAM)
{
// macro_rules! macro item
std::unique_ptr<AST::Item> item (
parse_macro_rules_def (std::move (outer_attrs)));
return ExprOrStmt (std::move (item));
}
- else
- {
- break;
- }
+ gcc_fallthrough ();
+ case SUPER:
+ case SELF:
+ case SELF_ALIAS:
+ case CRATE:
+ case SCOPE_RESOLUTION:
+ case DOLLAR_SIGN: {
+ AST::PathInExpression path = parse_path_in_expression ();
+ std::unique_ptr<AST::Expr> null_denotation;
+
+ if (lexer.peek_token ()->get_id () == EXCLAM)
+ {
+ std::unique_ptr<AST::MacroInvocation> invoc
+ = parse_macro_invocation_partial (std::move (path),
+ std::move (outer_attrs));
+
+ if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
+ {
+ invoc->add_semicolon ();
+ // Macro invocation with semicolon.
+ return ExprOrStmt (
+ std::unique_ptr<AST::Stmt> (std::move (invoc)));
+ }
+
+ TokenId after_macro = lexer.peek_token ()->get_id ();
+
+ if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
+ == AST::CURLY
+ && after_macro != DOT && after_macro != QUESTION_MARK)
+ {
+ rust_debug ("braced macro statement");
+ return ExprOrStmt (
+ std::unique_ptr<AST::Stmt> (std::move (invoc)));
+ }
+
+ null_denotation = std::move (invoc);
+ }
+ else
+ {
+ null_denotation
+ = null_denotation_path (std::move (path), {}, restrictions);
+ }
+
+ expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
+ std::move (outer_attrs), restrictions);
+ break;
+ }
default:
+ /* expression statement or expression itself - parse
+ * expression then make it statement if semi afterwards */
+ expr = parse_expr (std::move (outer_attrs), restrictions);
break;
}
- /* expression statement or expression itself - parse
- * expression then make it statement if semi afterwards */
-
- std::unique_ptr<AST::Expr> expr
- = parse_expr (std::move (outer_attrs), restrictions);
-
const_TokenPtr after_expr = lexer.peek_token ();
if (after_expr->get_id () == SEMICOLON)
{
@@ -11715,251 +11806,6 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr ()
return ExprOrStmt (std::move (expr));
}
-/* Parses a statement or expression beginning with a path (i.e. macro,
- * struct/enum, or path expr) */
-template <typename ManagedTokenSource>
-ExprOrStmt
-Parser<ManagedTokenSource>::parse_path_based_stmt_or_expr (
- AST::AttrVec outer_attrs)
-{
- // attempt to parse path
- Location stmt_or_expr_loc = lexer.peek_token ()->get_locus ();
- AST::PathInExpression path = parse_path_in_expression ();
-
- // branch on next token
- const_TokenPtr t2 = lexer.peek_token ();
- switch (t2->get_id ())
- {
- case EXCLAM: {
- /* macro invocation or macro invocation semi - depends on whether
- * there is a final ';' */
- // convert path in expr to simple path (as that is used in macros)
- AST::SimplePath macro_path = path.as_simple_path ();
- if (macro_path.is_empty ())
- {
- Error error (t2->get_locus (),
- "failed to convert parsed path to simple "
- "path (for macro invocation or semi)");
- add_error (std::move (error));
-
- return ExprOrStmt::create_error ();
- }
-
- // skip exclamation mark
- lexer.skip_token ();
-
- const_TokenPtr t3 = lexer.peek_token ();
- Location tok_tree_loc = t3->get_locus ();
-
- AST::DelimType type = AST::PARENS;
- switch (t3->get_id ())
- {
- case LEFT_PAREN:
- type = AST::PARENS;
- break;
- case LEFT_SQUARE:
- type = AST::SQUARE;
- break;
- case LEFT_CURLY:
- type = AST::CURLY;
- break;
- default:
- add_error (
- Error (t3->get_locus (),
- "unrecognised token %qs in macro invocation - (opening) "
- "delimiter expected",
- t3->get_token_description ()));
-
- return ExprOrStmt::create_error ();
- }
- lexer.skip_token ();
-
- // 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
- while (!token_id_matches_delims (t3->get_id (), type))
- {
- std::unique_ptr<AST::TokenTree> tree = parse_token_tree ();
-
- if (tree == nullptr)
- {
- Error error (t3->get_locus (),
- "failed to parse token tree for macro "
- "invocation (or semi) - "
- "found %qs",
- t3->get_token_description ());
- add_error (std::move (error));
-
- return ExprOrStmt::create_error ();
- }
-
- token_trees.push_back (std::move (tree));
-
- 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))
- {
- // tokens match opening delimiter, so skip.
- lexer.skip_token ();
-
- /* with curly bracketed macros, assume it is a macro invocation
- * unless a semicolon is explicitly put at the end. this is not
- * necessarily true (i.e. context-dependence) and so may have to
- * be fixed up via HACKs in semantic analysis (by checking whether
- * it is the last elem in the vector). */
-
- AST::DelimTokenTree delim_tok_tree (type, std::move (token_trees),
- tok_tree_loc);
- AST::MacroInvocData invoc_data (std::move (macro_path),
- std::move (delim_tok_tree));
-
- if (lexer.peek_token ()->get_id () == SEMICOLON)
- {
- lexer.skip_token ();
-
- auto stmt
- = AST::MacroInvocation::Regular (std::move (invoc_data),
- std::move (outer_attrs),
- stmt_or_expr_loc, true);
- return ExprOrStmt (std::move (stmt));
- }
-
- // otherwise, create macro invocation
- auto expr = AST::MacroInvocation::Regular (std::move (invoc_data),
- std::move (outer_attrs),
- stmt_or_expr_loc, false);
- return ExprOrStmt (std::move (expr));
- }
- else
- {
- // tokens don't match opening delimiters, so produce error
- Error error (
- t2->get_locus (),
- "unexpected token %qs - expecting closing delimiter %qs (for a "
- "macro invocation)",
- t2->get_token_description (),
- (type == AST::PARENS ? ")" : (type == AST::SQUARE ? "]" : "}")));
- add_error (std::move (error));
-
- return ExprOrStmt::create_error ();
- }
- }
- case LEFT_CURLY: {
- /* definitely not a block:
- * path '{' ident ','
- * path '{' ident ':' [anything] ','
- * path '{' ident ':' [not a type]
- * otherwise, assume block expr and thus path */
- bool not_a_block = lexer.peek_token (1)->get_id () == IDENTIFIER
- && (lexer.peek_token (2)->get_id () == COMMA
- || (lexer.peek_token (2)->get_id () == COLON
- && (lexer.peek_token (4)->get_id () == COMMA
- || !can_tok_start_type (
- lexer.peek_token (3)->get_id ()))));
- std::unique_ptr<AST::ExprWithoutBlock> expr = nullptr;
-
- if (not_a_block)
- {
- /* assume struct expr struct (as struct-enum disambiguation
- * requires name lookup) again, make statement if final ';' */
- expr = parse_struct_expr_struct_partial (std::move (path),
- std::move (outer_attrs));
- if (expr == nullptr)
- {
- Error error (t2->get_locus (),
- "failed to parse struct expr struct");
- add_error (std::move (error));
-
- return ExprOrStmt::create_error ();
- }
- }
- else
- {
- // assume path - make statement if final ';'
- // lexer.skip_token();
-
- // HACK: add outer attrs to path
- path.set_outer_attrs (std::move (outer_attrs));
- expr = std::unique_ptr<AST::PathInExpression> (
- new AST::PathInExpression (std::move (path)));
- }
-
- // determine if statement if ends with semicolon
- if (lexer.peek_token ()->get_id () == SEMICOLON)
- {
- // statement
- lexer.skip_token ();
- std::unique_ptr<AST::ExprStmt> stmt (
- new AST::ExprStmt (std::move (expr), stmt_or_expr_loc, true));
- return ExprOrStmt (std::move (stmt));
- }
-
- // otherwise, expression
- return ExprOrStmt (std::move (expr));
- }
- case LEFT_PAREN: {
- /* assume struct expr tuple (as struct-enum disambiguation requires
- * name lookup) again, make statement if final ';' */
- std::unique_ptr<AST::CallExpr> struct_expr
- = parse_struct_expr_tuple_partial (std::move (path),
- std::move (outer_attrs));
- if (struct_expr == nullptr)
- {
- Error error (t2->get_locus (), "failed to parse struct expr tuple");
- add_error (std::move (error));
-
- return ExprOrStmt::create_error ();
- }
-
- // determine if statement if ends with semicolon
- if (lexer.peek_token ()->get_id () == SEMICOLON)
- {
- // statement
- lexer.skip_token ();
- std::unique_ptr<AST::ExprStmt> stmt (
- new AST::ExprStmt (std::move (struct_expr), stmt_or_expr_loc,
- true));
- return ExprOrStmt (std::move (stmt));
- }
-
- // otherwise, expression
- return ExprOrStmt (std::move (struct_expr));
- }
- default: {
- // assume path - make statement if final ';'
- // lexer.skip_token();
-
- // HACK: replace outer attributes in path
- path.set_outer_attrs (std::move (outer_attrs));
- std::unique_ptr<AST::PathInExpression> expr (
- new AST::PathInExpression (std::move (path)));
-
- if (lexer.peek_token ()->get_id () == SEMICOLON)
- {
- lexer.skip_token ();
-
- std::unique_ptr<AST::ExprStmt> stmt (
- new AST::ExprStmt (std::move (expr), stmt_or_expr_loc, true));
- return ExprOrStmt (std::move (stmt));
- }
-
- return ExprOrStmt (std::move (expr));
- }
- }
-}
-
// Parses a struct expression field.
template <typename ManagedTokenSource>
std::unique_ptr<AST::StructExprField>
@@ -12045,135 +11891,6 @@ Parser<ManagedTokenSource>::parse_struct_expr_field ()
}
}
-// Parses a macro invocation or macro invocation semi.
-template <typename ManagedTokenSource>
-ExprOrStmt
-Parser<ManagedTokenSource>::parse_macro_invocation_maybe_semi (
- AST::AttrVec outer_attrs)
-{
- Location macro_locus = lexer.peek_token ()->get_locus ();
- AST::SimplePath macro_path = parse_simple_path ();
- if (macro_path.is_empty ())
- {
- Error error (lexer.peek_token ()->get_locus (),
- "failed to parse simple path in macro invocation or semi");
- add_error (std::move (error));
-
- return ExprOrStmt::create_error ();
- }
-
- if (!skip_token (EXCLAM))
- {
- return ExprOrStmt::create_error ();
- }
-
- const_TokenPtr t3 = lexer.peek_token ();
- Location tok_tree_loc = t3->get_locus ();
-
- AST::DelimType type = AST::PARENS;
- switch (t3->get_id ())
- {
- case LEFT_PAREN:
- type = AST::PARENS;
- break;
- case LEFT_SQUARE:
- type = AST::SQUARE;
- break;
- case LEFT_CURLY:
- type = AST::CURLY;
- break;
- default:
- add_error (
- Error (t3->get_locus (),
- "unrecognised token %qs in macro invocation - (opening) "
- "delimiter expected",
- t3->get_token_description ()));
-
- return ExprOrStmt::create_error ();
- }
- lexer.skip_token ();
-
- // 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
- while (!token_id_matches_delims (t3->get_id (), type))
- {
- std::unique_ptr<AST::TokenTree> tree = parse_token_tree ();
-
- if (tree == nullptr)
- {
- Error error (t3->get_locus (),
- "failed to parse token tree for macro invocation (or "
- "semi) - found %qs",
- t3->get_token_description ());
- add_error (std::move (error));
-
- return ExprOrStmt::create_error ();
- }
-
- token_trees.push_back (std::move (tree));
-
- 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))
- {
- // tokens match opening delimiter, so skip.
- lexer.skip_token ();
-
- /* with curly bracketed macros, assume it is a macro invocation unless
- * a semicolon is explicitly put at the end. this is not necessarily
- * true (i.e. context-dependence) and so may have to be fixed up via
- * HACKs in semantic analysis (by checking whether it is the last elem
- * in the vector). */
-
- AST::DelimTokenTree delim_tok_tree (type, std::move (token_trees),
- tok_tree_loc);
- AST::MacroInvocData invoc_data (std::move (macro_path),
- std::move (delim_tok_tree));
-
- if (lexer.peek_token ()->get_id () == SEMICOLON)
- {
- lexer.skip_token ();
-
- auto stmt = AST::MacroInvocation::Regular (std::move (invoc_data),
- std::move (outer_attrs),
- macro_locus, true);
- return ExprOrStmt (std::move (stmt));
- }
-
- // otherwise, create macro invocation
- auto expr
- = AST::MacroInvocation::Regular (std::move (invoc_data),
- std::move (outer_attrs), macro_locus);
- return ExprOrStmt (std::move (expr));
- }
- else
- {
- const_TokenPtr t = lexer.peek_token ();
- // tokens don't match opening delimiters, so produce error
- Error error (
- t->get_locus (),
- "unexpected token %qs - expecting closing delimiter %qs (for a "
- "macro invocation)",
- t->get_token_description (),
- (type == AST::PARENS ? ")" : (type == AST::SQUARE ? "]" : "}")));
- add_error (std::move (error));
-
- return ExprOrStmt::create_error ();
- }
-}
-
// "Unexpected token" panic mode - flags gcc error at unexpected token
template <typename ManagedTokenSource>
void
@@ -12376,13 +12093,24 @@ Parser<ManagedTokenSource>::parse_expr (int right_binding_power,
lexer.skip_token ();
- bool expr_can_be_stmt = restrictions.expr_can_be_stmt;
- restrictions.expr_can_be_stmt = false;
+ ParseRestrictions null_denotation_restrictions = restrictions;
+ null_denotation_restrictions.expr_can_be_stmt = false;
// parse null denotation (unary part of expression)
std::unique_ptr<AST::Expr> expr
- = null_denotation (current_token, {}, restrictions);
+ = null_denotation (current_token, {}, null_denotation_restrictions);
+ return left_denotations (std::move (expr), right_binding_power,
+ std::move (outer_attrs), restrictions);
+}
+
+template <typename ManagedTokenSource>
+std::unique_ptr<AST::Expr>
+Parser<ManagedTokenSource>::left_denotations (std::unique_ptr<AST::Expr> expr,
+ int right_binding_power,
+ AST::AttrVec outer_attrs,
+ ParseRestrictions restrictions)
+{
if (expr == nullptr)
{
// DEBUG
@@ -12390,9 +12118,9 @@ Parser<ManagedTokenSource>::parse_expr (int right_binding_power,
return nullptr;
}
- current_token = lexer.peek_token ();
+ const_TokenPtr current_token = lexer.peek_token ();
- if (expr_can_be_stmt && !expr->is_expr_without_block ()
+ if (restrictions.expr_can_be_stmt && !expr->is_expr_without_block ()
&& current_token->get_id () != DOT
&& current_token->get_id () != QUESTION_MARK)
{
@@ -12401,6 +12129,8 @@ Parser<ManagedTokenSource>::parse_expr (int right_binding_power,
return expr;
}
+ restrictions.expr_can_be_stmt = false;
+
// stop parsing if find lower priority token - parse higher priority first
while (right_binding_power < left_binding_power (current_token))
{
@@ -12449,7 +12179,12 @@ Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok,
switch (tok->get_id ())
{
- case IDENTIFIER: {
+ case IDENTIFIER:
+ case SELF:
+ case SELF_ALIAS:
+ case DOLLAR_SIGN:
+ case CRATE:
+ case SUPER: {
// DEBUG
rust_debug ("beginning null denotation identifier handling");
@@ -12457,88 +12192,126 @@ Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok,
* struct/enum, or just path info from it */
AST::PathInExpression path = parse_path_in_expression_pratt (tok);
- // DEBUG:
- rust_debug ("finished null denotation identifier path parsing - "
- "next is branching");
+ return null_denotation_path (std::move (path), std::move (outer_attrs),
+ restrictions);
+ }
+ case SCOPE_RESOLUTION: {
+ // TODO: fix: this is for global paths, i.e. std::string::whatever
+ Error error (tok->get_locus (),
+ "found null denotation scope resolution operator, and "
+ "have not written handling for it");
+ add_error (std::move (error));
- // branch on next token
- const_TokenPtr t = lexer.peek_token ();
- switch (t->get_id ())
+ return nullptr;
+ }
+ default:
+ return null_denotation_not_path (std::move (tok), std::move (outer_attrs),
+ restrictions);
+ }
+}
+
+// Handling of expresions that start with a path for `null_denotation`.
+template <typename ManagedTokenSource>
+std::unique_ptr<AST::Expr>
+Parser<ManagedTokenSource>::null_denotation_path (
+ AST::PathInExpression path, AST::AttrVec outer_attrs,
+ ParseRestrictions restrictions)
+{
+ rust_debug ("parsing null denotation after path");
+
+ // HACK: always make "self" by itself a path (regardless of next
+ // tokens)
+ if (path.is_single_segment () && path.get_segments ()[0].is_lower_self_seg ())
+ {
+ // HACK: add outer attrs to path
+ path.set_outer_attrs (std::move (outer_attrs));
+ return std::unique_ptr<AST::PathInExpression> (
+ new AST::PathInExpression (std::move (path)));
+ }
+
+ // branch on next token
+ const_TokenPtr t = lexer.peek_token ();
+ switch (t->get_id ())
+ {
+ case EXCLAM:
+ // macro
+ return parse_macro_invocation_partial (std::move (path),
+ std::move (outer_attrs));
+ case LEFT_CURLY: {
+ bool not_a_block = lexer.peek_token (1)->get_id () == IDENTIFIER
+ && (lexer.peek_token (2)->get_id () == COMMA
+ || (lexer.peek_token (2)->get_id () == COLON
+ && (lexer.peek_token (4)->get_id () == COMMA
+ || !can_tok_start_type (
+ lexer.peek_token (3)->get_id ()))));
+
+ /* definitely not a block:
+ * path '{' ident ','
+ * path '{' ident ':' [anything] ','
+ * path '{' ident ':' [not a type]
+ * otherwise, assume block expr and thus path */
+ // DEBUG
+ rust_debug ("values of lookahead: '%s' '%s' '%s' '%s' ",
+ lexer.peek_token (1)->get_token_description (),
+ lexer.peek_token (2)->get_token_description (),
+ lexer.peek_token (3)->get_token_description (),
+ lexer.peek_token (4)->get_token_description ());
+
+ rust_debug ("can be struct expr: '%s', not a block: '%s'",
+ restrictions.can_be_struct_expr ? "true" : "false",
+ not_a_block ? "true" : "false");
+
+ // struct/enum expr struct
+ if (!restrictions.can_be_struct_expr && !not_a_block)
{
- case EXCLAM:
- // macro
- return parse_macro_invocation_partial (std::move (path),
- std::move (outer_attrs),
- restrictions);
- case LEFT_CURLY: {
- bool not_a_block
- = lexer.peek_token (1)->get_id () == IDENTIFIER
- && (lexer.peek_token (2)->get_id () == COMMA
- || (lexer.peek_token (2)->get_id () == COLON
- && (lexer.peek_token (4)->get_id () == COMMA
- || !can_tok_start_type (
- lexer.peek_token (3)->get_id ()))));
-
- /* definitely not a block:
- * path '{' ident ','
- * path '{' ident ':' [anything] ','
- * path '{' ident ':' [not a type]
- * otherwise, assume block expr and thus path */
- // DEBUG
- rust_debug ("values of lookahead: '%s' '%s' '%s' '%s' ",
- lexer.peek_token (1)->get_token_description (),
- lexer.peek_token (2)->get_token_description (),
- lexer.peek_token (3)->get_token_description (),
- lexer.peek_token (4)->get_token_description ());
-
- rust_debug ("can be struct expr: '%s', not a block: '%s'",
- restrictions.can_be_struct_expr ? "true" : "false",
- not_a_block ? "true" : "false");
-
- // struct/enum expr struct
- if (!restrictions.can_be_struct_expr && !not_a_block)
- {
- // HACK: add outer attrs to path
- path.set_outer_attrs (std::move (outer_attrs));
- return std::unique_ptr<AST::PathInExpression> (
- new AST::PathInExpression (std::move (path)));
- }
- return parse_struct_expr_struct_partial (std::move (path),
- std::move (outer_attrs));
- }
- case LEFT_PAREN:
- // struct/enum expr tuple
- if (!restrictions.can_be_struct_expr)
- {
- // HACK: add outer attrs to path
- path.set_outer_attrs (std::move (outer_attrs));
- return std::unique_ptr<AST::PathInExpression> (
- new AST::PathInExpression (std::move (path)));
- }
- return parse_struct_expr_tuple_partial (std::move (path),
- std::move (outer_attrs));
- default:
- // assume path is returned if not single segment
- if (path.is_single_segment ())
- {
- // have to return an identifier expression or something, idk
- /* HACK: may have to become permanent, but this is my current
- * identifier expression */
- return std::unique_ptr<AST::IdentifierExpr> (
- new AST::IdentifierExpr (tok->get_str (), {},
- tok->get_locus ()));
- }
// HACK: add outer attrs to path
path.set_outer_attrs (std::move (outer_attrs));
return std::unique_ptr<AST::PathInExpression> (
new AST::PathInExpression (std::move (path)));
}
- gcc_unreachable ();
+ return parse_struct_expr_struct_partial (std::move (path),
+ std::move (outer_attrs));
}
- /* FIXME: delegate to parse_literal_expr instead? would have to rejig
- * tokens and whatever. */
- /* FIXME: could also be path expression (and hence macro expression,
- * struct/enum expr) */
+ case LEFT_PAREN:
+ // struct/enum expr tuple
+ if (!restrictions.can_be_struct_expr)
+ {
+ // assume path is returned
+ // HACK: add outer attributes to path
+ path.set_outer_attrs (std::move (outer_attrs));
+ return std::unique_ptr<AST::PathInExpression> (
+ new AST::PathInExpression (std::move (path)));
+ }
+ return parse_struct_expr_tuple_partial (std::move (path),
+ std::move (outer_attrs));
+ default:
+ // assume path is returned if not single segment
+ if (path.is_single_segment ())
+ {
+ // FIXME: This should probably be returned as a path.
+ /* HACK: may have to become permanent, but this is my current
+ * identifier expression */
+ return std::unique_ptr<AST::IdentifierExpr> (new AST::IdentifierExpr (
+ path.get_segments ()[0].get_ident_segment ().as_string (), {},
+ path.get_locus ()));
+ }
+ // HACK: add outer attrs to path
+ path.set_outer_attrs (std::move (outer_attrs));
+ return std::unique_ptr<AST::PathInExpression> (
+ new AST::PathInExpression (std::move (path)));
+ }
+ gcc_unreachable ();
+}
+
+// Handling of expresions that do not start with a path for `null_denotation`.
+template <typename ManagedTokenSource>
+std::unique_ptr<AST::Expr>
+Parser<ManagedTokenSource>::null_denotation_not_path (
+ const_TokenPtr tok, AST::AttrVec outer_attrs, ParseRestrictions restrictions)
+{
+ switch (tok->get_id ())
+ {
+ // FIXME: Handle in null_denotation_path?
case LEFT_SHIFT:
case LEFT_ANGLE: {
// qualified path
@@ -12549,8 +12322,10 @@ Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok,
return std::unique_ptr<AST::QualifiedPathInExpression> (
new AST::QualifiedPathInExpression (std::move (path)));
}
- // FIXME: for literal exprs, should outer attrs be passed in or just
- // ignored?
+ // FIXME: delegate to parse_literal_expr instead? would have to rejig
+ // tokens and whatever.
+ // FIXME: for literal exprs, outer attrs should be passed in, and later
+ // error if it does not make up the entire statement.
case INT_LITERAL:
// we should check the range, but ignore for now
// encode as int?
@@ -12721,97 +12496,6 @@ Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok,
new AST::BorrowExpr (std::move (expr), is_mut_borrow, true,
std::move (outer_attrs), tok->get_locus ()));
}
- case SCOPE_RESOLUTION: {
- // TODO: fix: this is for global paths, i.e. std::string::whatever
- Error error (tok->get_locus (),
- "found null denotation scope resolution operator, and "
- "have not written handling for it");
- add_error (std::move (error));
-
- return nullptr;
- }
- case SELF:
- case SELF_ALIAS:
- case DOLLAR_SIGN:
- case CRATE:
- case SUPER: {
- // DEBUG
- rust_debug ("beginning null denotation "
- "self/self-alias/dollar/crate/super handling");
-
- /* best option: parse as path, then extract identifier, macro,
- * struct/enum, or just path info from it */
- AST::PathInExpression path = parse_path_in_expression_pratt (tok);
-
- // DEBUG
- rust_debug (
- "just finished parsing path (going to disambiguate) - peeked "
- "token is '%s'",
- lexer.peek_token ()->get_token_description ());
-
- // HACK: always make "self" by itself a path (regardless of next
- // tokens)
- if (tok->get_id () == SELF && path.is_single_segment ())
- {
- // HACK: add outer attrs to path
- path.set_outer_attrs (std::move (outer_attrs));
- return std::unique_ptr<AST::PathInExpression> (
- new AST::PathInExpression (std::move (path)));
- }
-
- // branch on next token
- const_TokenPtr t = lexer.peek_token ();
- switch (t->get_id ())
- {
- case EXCLAM:
- // macro
- return parse_macro_invocation_partial (std::move (path),
- std::move (outer_attrs));
- case LEFT_CURLY: {
- // struct/enum expr struct
- rust_debug ("can_be_struct_expr: %s",
- restrictions.can_be_struct_expr ? "true" : "false");
-
- bool not_a_block
- = lexer.peek_token (1)->get_id () == IDENTIFIER
- && (lexer.peek_token (2)->get_id () == COMMA
- || (lexer.peek_token (2)->get_id () == COLON
- && (lexer.peek_token (4)->get_id () == COMMA
- || !can_tok_start_type (
- lexer.peek_token (3)->get_id ()))));
-
- if (!restrictions.can_be_struct_expr && !not_a_block)
- {
- // assume path is returned
- // HACK: add outer attributes to path
- path.set_outer_attrs (std::move (outer_attrs));
- return std::unique_ptr<AST::PathInExpression> (
- new AST::PathInExpression (std::move (path)));
- }
- return parse_struct_expr_struct_partial (std::move (path),
- std::move (outer_attrs));
- }
- case LEFT_PAREN:
- // struct/enum expr tuple
- if (!restrictions.can_be_struct_expr)
- {
- // assume path is returned
- // HACK: add outer attributes to path
- path.set_outer_attrs (std::move (outer_attrs));
- return std::unique_ptr<AST::PathInExpression> (
- new AST::PathInExpression (std::move (path)));
- }
- return parse_struct_expr_tuple_partial (std::move (path),
- std::move (outer_attrs));
- default:
- // assume path is returned
- // HACK: add outer attributes to path
- path.set_outer_attrs (std::move (outer_attrs));
- return std::unique_ptr<AST::PathInExpression> (
- new AST::PathInExpression (std::move (path)));
- }
- gcc_unreachable ();
- }
case OR:
case PIPE:
case MOVE:
@@ -14407,9 +14091,7 @@ Parser<ManagedTokenSource>::parse_macro_invocation_partial (
return AST::MacroInvocation::Regular (
AST::MacroInvocData (std::move (converted_path), std::move (tok_tree)),
- std::move (outer_attrs), macro_locus,
- restrictions.expr_can_be_stmt
- && lexer.peek_token ()->get_id () == SEMICOLON);
+ std::move (outer_attrs), macro_locus);
}
/* Parses a struct expr struct with a path in expression already parsed (but
diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h
index 74313df..6202574 100644
--- a/gcc/rust/parse/rust-parse.h
+++ b/gcc/rust/parse/rust-parse.h
@@ -340,6 +340,17 @@ private:
null_denotation (const_TokenPtr t, AST::AttrVec outer_attrs = AST::AttrVec (),
ParseRestrictions restrictions = ParseRestrictions ());
std::unique_ptr<AST::Expr>
+ null_denotation_path (AST::PathInExpression path, AST::AttrVec outer_attrs,
+ ParseRestrictions restrictions = ParseRestrictions ());
+ std::unique_ptr<AST::Expr>
+ null_denotation_not_path (const_TokenPtr t, AST::AttrVec outer_attrs,
+ ParseRestrictions restrictions
+ = ParseRestrictions ());
+ std::unique_ptr<AST::Expr>
+ left_denotations (std::unique_ptr<AST::Expr> null_denotation,
+ int right_binding_power, AST::AttrVec outer_attrs,
+ ParseRestrictions restrictions = ParseRestrictions ());
+ std::unique_ptr<AST::Expr>
left_denotation (const_TokenPtr t, std::unique_ptr<AST::Expr> left,
AST::AttrVec outer_attrs = AST::AttrVec (),
ParseRestrictions restrictions = ParseRestrictions ());
@@ -637,12 +648,10 @@ private:
std::unique_ptr<AST::LetStmt> parse_let_stmt (AST::AttrVec outer_attrs,
ParseRestrictions restrictions
= ParseRestrictions ());
- std::unique_ptr<AST::ExprStmt> parse_expr_stmt (AST::AttrVec outer_attrs,
- ParseRestrictions restrictions
- = ParseRestrictions ());
+ std::unique_ptr<AST::Stmt> parse_expr_stmt (AST::AttrVec outer_attrs,
+ ParseRestrictions restrictions
+ = ParseRestrictions ());
ExprOrStmt parse_stmt_or_expr ();
- ExprOrStmt parse_macro_invocation_maybe_semi (AST::AttrVec outer_attrs);
- ExprOrStmt parse_path_based_stmt_or_expr (AST::AttrVec outer_attrs);
// Pattern-related
std::unique_ptr<AST::Pattern> parse_literal_or_range_pattern ();
diff --git a/gcc/testsuite/rust/compile/braced_macro_arm.rs b/gcc/testsuite/rust/compile/braced_macro_arm.rs
new file mode 100644
index 0000000..1446878
--- /dev/null
+++ b/gcc/testsuite/rust/compile/braced_macro_arm.rs
@@ -0,0 +1,19 @@
+// Braced macro invocations are not allowed as match arms without a semicolon,
+// even though they are allowed as statements without a semicolon.
+
+macro_rules! m {
+ () => { 1 }
+}
+
+fn h(c: bool) {
+ match c {
+ // { dg-error "failed to parse statement or expression in block expression" "" { target *-*-* } .-1 }
+ true => m! {}
+ false => ()
+ // { dg-error "exprwithoutblock requires comma after match case expression in match arm \\(if not final case\\)" "" { target *-*-* } .-1 }
+ // { dg-error "unrecognised token .false. for start of item" "" { target *-*-* } .-2 }
+ // { dg-error "failed to parse item in crate" "" { target *-*-* } .-3 }
+ };
+}
+
+fn main () {}
diff --git a/gcc/testsuite/rust/compile/braced_macro_statements1.rs b/gcc/testsuite/rust/compile/braced_macro_statements1.rs
new file mode 100644
index 0000000..e3ed068
--- /dev/null
+++ b/gcc/testsuite/rust/compile/braced_macro_statements1.rs
@@ -0,0 +1,15 @@
+macro_rules! m {
+ () => { bar() }
+}
+
+fn bar () {}
+
+fn foo() {
+ m!{}
+ m!{}
+}
+
+fn main() -> i32 {
+ foo();
+ 0
+}
diff --git a/gcc/testsuite/rust/compile/braced_macro_statements2.rs b/gcc/testsuite/rust/compile/braced_macro_statements2.rs
new file mode 100644
index 0000000..e7b6ab3
--- /dev/null
+++ b/gcc/testsuite/rust/compile/braced_macro_statements2.rs
@@ -0,0 +1,15 @@
+// Output of statement macros is always parsed as a statement, so no semicolon
+// is needed on the inner macro.
+
+macro_rules! m {
+ (macro) => { m!(stmts) };
+ (stmts) => { let x = 3; x - 3 }
+}
+
+fn foo() -> i32 {
+ m!{macro}
+}
+
+fn main() -> i32 {
+ foo()
+}
diff --git a/gcc/testsuite/rust/compile/braced_macro_statements3.rs b/gcc/testsuite/rust/compile/braced_macro_statements3.rs
new file mode 100644
index 0000000..a19f4fc
--- /dev/null
+++ b/gcc/testsuite/rust/compile/braced_macro_statements3.rs
@@ -0,0 +1,11 @@
+macro_rules! unroll {
+ {} => {}
+}
+
+pub fn foo() {
+ let mut _a = 14;
+ unroll! {}
+ let mut _b = 13;
+}
+
+fn main() -> i32 { 0 }
diff --git a/gcc/testsuite/rust/compile/issue-2225.rs b/gcc/testsuite/rust/compile/issue-2225.rs
index 53757c1..4ae40e8 100644
--- a/gcc/testsuite/rust/compile/issue-2225.rs
+++ b/gcc/testsuite/rust/compile/issue-2225.rs
@@ -4,7 +4,7 @@ macro_rules! foo {
}
macro_rules! bar {
- () => {let $_a = 12;} // { dg-error "unrecognised token" }
+ () => {let $_a = 12;} // { dg-error "expecting .;. but .\\$. found" }
}
pub fn main() -> i32 {