public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-7679] gccrs: Parse semicolons in more cases for statement macros
@ 2024-01-16 17:53 Arthur Cohen
0 siblings, 0 replies; only message in thread
From: Arthur Cohen @ 2024-01-16 17:53 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:8bc4ce7c40be159c83d623beb4cb074e1b5b0daa
commit r14-7679-g8bc4ce7c40be159c83d623beb4cb074e1b5b0daa
Author: Matthew Jasper <mjjasper1@gmail.com>
Date: Thu Jun 8 20:14:47 2023 +0100
gccrs: Parse semicolons in more cases for statement macros
gccrs: Parse statement macros as statements.
gcc/rust/ChangeLog:
* ast/rust-ast.h (MacroInvocation::add_semicolon): New method.
(Expr::to_stmt): Remove method.
* ast/rust-macro.h (MacroInvocation::add_semicolon): Add override.
(MacroInvocation::to_stmt): Remove override.
* ast/rust-stmt.h: Remove use of Expr::to_stmt.
(ExprStmt::add_semicolon): Add override.
* expand/rust-macro-expand.h (struct MacroExpander):
Add EXPR/STMT and remove BLOCK from ContextType.
* expand/rust-expand-visitor.cc (ExpandVisitor::maybe_expand_expr): Use EXPR context.
(ExpandVisitor::expand_inner_stmts): Use STMT context.
(ExpandVisitor::visitor): Remove use of BLOCK context.
* expand/rust-macro-expand.cc (parse_many): Pass enum by value.
(transcribe_on_delimiter): Remove function.
(transcribe_context): Use EXPR/STMT contexts.
(MacroExpander::parse_proc_macro_output): Use EXPR/STMT contexts.
(transcribe_many_stmts): Parse statements with semicolons.
* parse/rust-parse-impl.h (Parser::parse_stmt):
Delegate macro parsing to parse_expr_stmt, check for ! after macro_rules.
(Parser::parse_let_stmt): Work around lack of NT tokens.
(Parser::parse_expr_stmt): Handle statements at end of macro expansions.
(Parser::parse_expr_stmt): Parse macro statements/expression statements
starting with a macro.
(Parser::parse_match_expr): Don't modify flag unnecessarily.
(Parser::parse_stmt_or_expr):
Parse macro statements/expression statements starting with a macro.
(Parser::parse_path_based_stmt_or_expr): Remove method.
(Parser::parse_macro_invocation_maybe_semi): Remove method.
(Parser::parse_expr): Move code into left_denotations.
(Parser::left_denotations): New method.
(Parser::null_denotation): Split out methods for cases with and without paths.
(Parser::null_denotation_path): New method.
(Parser::null_denotation_not_path): New method.
(Parser::parse_macro_invocation_partial): Don't check for semicolon here.
* parse/rust-parse.h: Update declarations.
(struct ParseRestrictions): Additional flag.
gcc/testsuite/ChangeLog:
* rust/compile/braced_macro_arm.rs: New test.
* rust/compile/braced_macro_statements1.rs: New test.
* rust/compile/braced_macro_statements2.rs: New test.
* rust/compile/braced_macro_statements3.rs: New test.
* rust/compile/issue-2225.rs: Update test.
* rust/compile/macro53.rs: New test.
Signed-off-by: Matthew Jasper <mjjasper1@gmail.com>
Diff:
---
gcc/rust/ast/rust-ast.h | 4 +-
gcc/rust/ast/rust-macro.h | 11 +-
gcc/rust/ast/rust-stmt.h | 10 +-
gcc/rust/expand/rust-expand-visitor.cc | 13 +-
gcc/rust/expand/rust-macro-expand.cc | 46 +-
gcc/rust/expand/rust-macro-expand.h | 3 +-
gcc/rust/parse/rust-parse-impl.h | 875 +++++++--------------
gcc/rust/parse/rust-parse.h | 22 +-
gcc/testsuite/rust/compile/braced_macro_arm.rs | 19 +
.../rust/compile/braced_macro_statements1.rs | 15 +
.../rust/compile/braced_macro_statements2.rs | 15 +
.../rust/compile/braced_macro_statements3.rs | 11 +
gcc/testsuite/rust/compile/issue-2225.rs | 2 +-
gcc/testsuite/rust/compile/macro53.rs | 10 +
14 files changed, 419 insertions(+), 637 deletions(-)
diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h
index 09566575a85..3c1f95a973f 100644
--- a/gcc/rust/ast/rust-ast.h
+++ b/gcc/rust/ast/rust-ast.h
@@ -904,6 +904,8 @@ public:
virtual bool is_expr () const { return false; }
+ virtual void add_semicolon () {}
+
protected:
Stmt () : node_id (Analysis::Mappings::get ()->get_next_node_id ()) {}
@@ -986,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 076ab978bc3..a0d1adc7de1 100644
--- a/gcc/rust/ast/rust-macro.h
+++ b/gcc/rust/ast/rust-macro.h
@@ -787,6 +787,8 @@ public:
return new MacroInvocation (*this);
}
+ void add_semicolon () override { is_semi_coloned = true; }
+
protected:
Item *clone_item_impl () const override
{
@@ -809,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 7496a376d8a..95a5a62bfa4 100644
--- a/gcc/rust/ast/rust-stmt.h
+++ b/gcc/rust/ast/rust-stmt.h
@@ -192,12 +192,18 @@ public:
bool is_item () const override final { return false; }
bool is_expr () const override final { return true; }
+
+ // Used for the last statement for statement macros with a trailing
+ // semicolon.
+ void add_semicolon () override final { semicolon_followed = true; }
+
std::string as_string () const override;
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 3601287be99..9183a63b9a9 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 a92bbdcb943..225049ad2e4 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -724,7 +724,7 @@ MacroExpander::match_repetition (Parser<MacroInvocLexer> &parser,
* Helper function to refactor calling a parsing function 0 or more times
*/
static AST::Fragment
-parse_many (Parser<MacroInvocLexer> &parser, TokenId &delimiter,
+parse_many (Parser<MacroInvocLexer> &parser, TokenId delimiter,
std::function<AST::SingleASTNode ()> parse_fn)
{
auto &lexer = parser.get_token_source ();
@@ -836,18 +836,22 @@ transcribe_many_trait_impl_items (Parser<MacroInvocLexer> &parser,
* @param delimiter Id of the token on which parsing should stop
*/
static AST::Fragment
-transcribe_many_stmts (Parser<MacroInvocLexer> &parser, TokenId &delimiter)
+transcribe_many_stmts (Parser<MacroInvocLexer> &parser, TokenId delimiter,
+ bool semicolon)
{
auto restrictions = ParseRestrictions ();
- restrictions.consume_semi = false;
-
- // FIXME: This is invalid! It needs to also handle cases where the macro
- // transcriber is an expression, but since the macro call is followed by
- // a semicolon, it's a valid ExprStmt
- return parse_many (parser, delimiter, [&parser, restrictions] () {
- auto stmt = parser.parse_stmt (restrictions);
- return AST::SingleASTNode (std::move (stmt));
- });
+ restrictions.allow_close_after_expr_stmt = true;
+
+ return parse_many (parser, delimiter,
+ [&parser, restrictions, delimiter, semicolon] () {
+ auto stmt = parser.parse_stmt (restrictions);
+ if (semicolon && stmt
+ && parser.peek_current_token ()->get_id ()
+ == delimiter)
+ stmt->add_semicolon ();
+
+ return AST::SingleASTNode (std::move (stmt));
+ });
}
/**
@@ -890,16 +894,6 @@ transcribe_type (Parser<MacroInvocLexer> &parser)
return AST::Fragment ({std::move (type)}, lexer.get_token_slice (start, end));
}
-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,
@@ -941,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 ();
}
}
@@ -1107,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 ();
@@ -1121,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 8ac84d513b2..1e3da0b2172 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 6eb5eb6e741..ff929d3c625 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:
@@ -6348,8 +6341,16 @@ Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs,
}
if (restrictions.consume_semi)
- if (!skip_token (SEMICOLON))
- return nullptr;
+ {
+ // `stmt` macro variables are parsed without a semicolon, but should be
+ // parsed as a full statement when interpolated. This should be handled
+ // by having the interpolated statement be distinguishable from normal
+ // tokens, e.g. by NT tokens.
+ if (restrictions.allow_close_after_expr_stmt)
+ maybe_skip_token (SEMICOLON);
+ else if (!skip_token (SEMICOLON))
+ return nullptr;
+ }
return std::unique_ptr<AST::LetStmt> (
new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type),
@@ -7261,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
@@ -7289,10 +7348,27 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
if (restrictions.consume_semi)
{
- if (skip_token (SEMICOLON))
- has_semi = true;
+ if (maybe_skip_token (SEMICOLON))
+ {
+ has_semi = true;
+ }
else if (expr->is_expr_without_block ())
- return nullptr;
+ {
+ if (restrictions.allow_close_after_expr_stmt)
+ {
+ TokenId id = lexer.peek_token ()->get_id ();
+ if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE)
+ {
+ expect_token (SEMICOLON);
+ return nullptr;
+ }
+ }
+ else
+ {
+ expect_token (SEMICOLON);
+ return nullptr;
+ }
+ }
}
return std::unique_ptr<AST::ExprStmt> (
@@ -8441,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);
@@ -11537,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
@@ -11589,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:
@@ -11624,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"
@@ -11638,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)
{
@@ -11690,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>
@@ -12020,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
@@ -12351,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
@@ -12365,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)
{
@@ -12376,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))
{
@@ -12424,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");
@@ -12432,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
@@ -12524,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?
@@ -12696,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:
@@ -14382,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 315d3fcdec6..62025745662 100644
--- a/gcc/rust/parse/rust-parse.h
+++ b/gcc/rust/parse/rust-parse.h
@@ -87,6 +87,9 @@ struct ParseRestrictions
bool expr_can_be_null = false;
bool expr_can_be_stmt = false;
bool consume_semi = true;
+ /* Macro invocations that are statements can expand without a semicolon after
+ * the final statement, if it's an expression statement. */
+ bool allow_close_after_expr_stmt = false;
};
// Parser implementation for gccrs.
@@ -337,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 ());
@@ -634,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 00000000000..14468786f50
--- /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 00000000000..e3ed068ef62
--- /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 00000000000..e7b6ab38102
--- /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 00000000000..a19f4fcea0a
--- /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 53757c1bae6..4ae40e88ace 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 {
diff --git a/gcc/testsuite/rust/compile/macro53.rs b/gcc/testsuite/rust/compile/macro53.rs
new file mode 100644
index 00000000000..efa2d4ba973
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macro53.rs
@@ -0,0 +1,10 @@
+macro_rules! numbers {
+ {} => { 1 2 }
+ // { dg-error "expecting .;. but .integer literal. found" "" { target *-*-* } .-1 }
+}
+
+pub fn foo() {
+ numbers!();
+}
+
+fn main() -> i32 { 0 }
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2024-01-16 17:53 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-16 17:53 [gcc r14-7679] gccrs: Parse semicolons in more cases for statement macros Arthur Cohen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).