Index: runtime/vm/parser.cc |
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
index 0b82d605eee84eba098f22cb639e916b64930003..7479a092e4ecc21b139fe5e83ca4697da6222262 100644 |
--- a/runtime/vm/parser.cc |
+++ b/runtime/vm/parser.cc |
@@ -6188,7 +6188,7 @@ SequenceNode* Parser::CloseAsyncGeneratorTryBlock(SequenceNode *body) { |
// No outer try statement |
CatchClauseNode::kInvalidTryIndex); |
finally_clause = NULL; |
- AddFinallyBlockToNode(true, node_to_inline, node); |
+ AddFinallyClauseToNode(true, node_to_inline, node); |
node_index++; |
} |
} while (finally_clause == NULL); |
@@ -8609,7 +8609,7 @@ AstNode* Parser::ParseAwaitForStatement(String* label_name) { |
context_var, |
outer_try_index); |
finally_clause = NULL; |
- AddFinallyBlockToNode(true, node_to_inline, node); |
+ AddFinallyClauseToNode(true, node_to_inline, node); |
node_index++; |
} |
} while (finally_clause == NULL); |
@@ -8973,15 +8973,19 @@ void Parser::SaveExceptionAndStacktrace(SequenceNode* statements, |
} |
-SequenceNode* Parser::ParseFinallyBlock( |
+SequenceNode* Parser::EnsureFinallyClause( |
+ bool parse, |
bool is_async, |
LocalVariable* exception_var, |
LocalVariable* stack_trace_var, |
LocalVariable* rethrow_exception_var, |
LocalVariable* rethrow_stack_trace_var) { |
- TRACE_PARSER("ParseFinallyBlock"); |
+ TRACE_PARSER("EnsureFinallyClause"); |
+ ASSERT(parse || (is_async && (try_stack_ != NULL))); |
OpenBlock(); |
- ExpectToken(Token::kLBRACE); |
+ if (parse) { |
+ ExpectToken(Token::kLBRACE); |
+ } |
if (try_stack_ != NULL) { |
try_stack_->enter_finally(); |
@@ -9017,13 +9021,15 @@ SequenceNode* Parser::ParseFinallyBlock( |
rethrow_stack_trace_var); |
} |
- ParseStatementSequence(); |
- ExpectToken(Token::kRBRACE); |
- SequenceNode* finally_block = CloseBlock(); |
+ if (parse) { |
+ ParseStatementSequence(); |
+ ExpectToken(Token::kRBRACE); |
+ } |
+ SequenceNode* finally_clause = CloseBlock(); |
if (try_stack_ != NULL) { |
try_stack_->exit_finally(); |
} |
- return finally_block; |
+ return finally_clause; |
} |
@@ -9067,19 +9073,19 @@ void Parser::AddNodeForFinallyInlining(AstNode* node) { |
} |
-// Add the inlined finally block to the specified node. |
-void Parser::AddFinallyBlockToNode(bool is_async, |
- AstNode* node, |
- InlinedFinallyNode* finally_node) { |
+// Add the inlined finally clause to the specified node. |
+void Parser::AddFinallyClauseToNode(bool is_async, |
+ AstNode* node, |
+ InlinedFinallyNode* finally_clause) { |
ReturnNode* return_node = node->AsReturnNode(); |
if (return_node != NULL) { |
parsed_function()->EnsureFinallyReturnTemp(is_async); |
- return_node->AddInlinedFinallyNode(finally_node); |
+ return_node->AddInlinedFinallyNode(finally_clause); |
return; |
} |
JumpNode* jump_node = node->AsJumpNode(); |
ASSERT(jump_node != NULL); |
- jump_node->AddInlinedFinallyNode(finally_node); |
+ jump_node->AddInlinedFinallyNode(finally_clause); |
} |
@@ -9464,31 +9470,39 @@ AstNode* Parser::ParseTryStatement(String* label_name) { |
const intptr_t outer_try_index = (outer_try != NULL) ? |
outer_try->try_index() : CatchClauseNode::kInvalidTryIndex; |
- // Finally parse the 'finally' block. |
- SequenceNode* finally_block = NULL; |
- if (CurrentToken() == Token::kFINALLY) { |
- ConsumeToken(); // Consume the 'finally'. |
+ // Finally, parse or generate the 'finally' clause. |
+ // A finally clause is required in async code to restore the saved try context |
+ // of an existing outer try. Generate a finally clause to this purpose if it |
+ // is not declared. |
+ SequenceNode* finally_clause = NULL; |
+ const bool parse = CurrentToken() == Token::kFINALLY; |
+ if (parse || (is_async && (try_stack_ != NULL))) { |
+ if (parse) { |
+ ConsumeToken(); // Consume the 'finally'. |
+ } |
const intptr_t finally_pos = TokenPos(); |
// Add the finally block to the exit points recorded so far. |
intptr_t node_index = 0; |
AstNode* node_to_inline = try_statement->GetNodeToInlineFinally(node_index); |
while (node_to_inline != NULL) { |
- finally_block = ParseFinallyBlock( |
+ finally_clause = EnsureFinallyClause( |
+ parse, |
is_async, |
exception_var, |
stack_trace_var, |
is_async ? saved_exception_var : exception_var, |
is_async ? saved_stack_trace_var : stack_trace_var); |
InlinedFinallyNode* node = new(Z) InlinedFinallyNode(finally_pos, |
- finally_block, |
+ finally_clause, |
context_var, |
outer_try_index); |
- AddFinallyBlockToNode(is_async, node_to_inline, node); |
+ AddFinallyClauseToNode(is_async, node_to_inline, node); |
node_index += 1; |
node_to_inline = try_statement->GetNodeToInlineFinally(node_index); |
tokens_iterator_.SetCurrentPosition(finally_pos); |
} |
- finally_block = ParseFinallyBlock( |
+ finally_clause = EnsureFinallyClause( |
+ parse, |
is_async, |
exception_var, |
stack_trace_var, |
@@ -9505,7 +9519,7 @@ AstNode* Parser::ParseTryStatement(String* label_name) { |
stack_trace_var, |
is_async ? saved_exception_var : exception_var, |
is_async ? saved_stack_trace_var : stack_trace_var, |
- (finally_block != NULL) ? |
+ (finally_clause != NULL) ? |
AllocateTryIndex() : CatchClauseNode::kInvalidTryIndex, |
needs_stack_trace); |
@@ -9513,7 +9527,7 @@ AstNode* Parser::ParseTryStatement(String* label_name) { |
// on the try/catch, close the block that's embedding the try statement |
// and attach the label to it. |
AstNode* try_catch_node = new(Z) TryCatchNode( |
- try_pos, try_block, context_var, catch_clause, finally_block, try_index); |
+ try_pos, try_block, context_var, catch_clause, finally_clause, try_index); |
if (try_label != NULL) { |
current_block_->statements->Add(try_catch_node); |