Restore try contexts when breaking out of async for loops
Restore the try context in the finally clause of the implicit
try-finally around await-for loops. This ensures that the context
is restored even when breaking out of the loop.
BUG=24935
R=fschneider@google.com, regis@google.com
Review URL: https://codereview.chromium.org/1661433003 .
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 2034a2f..bed681e 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -8719,7 +8719,7 @@
outer_try->try_index() : CatchClauseNode::kInvalidTryIndex;
// The finally block contains a call to cancel the stream.
- // :for-in-iter.cancel()
+ // :for-in-iter.cancel();
// Inline the finally block to the exit points in the try block.
intptr_t node_index = 0;
@@ -8729,6 +8729,17 @@
}
do {
OpenBlock();
+
+ // Restore the saved try context of the enclosing try block if one
+ // exists.
+ if (outer_saved_try_ctx != NULL) {
+ current_block_->statements->Add(new (Z) StoreLocalNode(
+ TokenPosition::kNoSource,
+ outer_saved_try_ctx,
+ new (Z) LoadLocalNode(TokenPosition::kNoSource,
+ outer_async_saved_try_ctx)));
+ }
+ // :for-in-iter.cancel();
ArgumentListNode* no_args =
new(Z) ArgumentListNode(TokenPosition::kNoSource);
current_block_->statements->Add(
@@ -8737,6 +8748,7 @@
Symbols::Cancel(),
no_args));
finally_clause = CloseBlock();
+
AstNode* node_to_inline = try_statement->GetNodeToInlineFinally(node_index);
if (node_to_inline != NULL) {
InlinedFinallyNode* node =
@@ -9127,7 +9139,7 @@
if (try_stack_ != NULL) {
try_stack_->enter_finally();
}
- // In case of async closures we need to restore the saved try index of an
+ // In case of async closures we need to restore the saved try context of an
// outer try block (if it exists). The current try block has already been
// removed from the stack of try blocks.
if (is_async) {
diff --git a/tests/language/regress_24935_test.dart b/tests/language/regress_24935_test.dart
new file mode 100644
index 0000000..53f6f49
--- /dev/null
+++ b/tests/language/regress_24935_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+S() => new Stream.fromIterable([1]);
+
+Future main() async {
+ L: for (var s = 0; s < 10; s++) {
+ await for (var s1 in S()){
+ await for (var s2 in S()){
+ continue L;
+ }
+ }
+ }
+ // Regression check: make sure throwing an exception
+ // after breaking out of the innermost loop does not
+ // crash the VM. In other words, the expected test
+ // outcome is an unhandled exception.
+ throw "ball"; /// 01: runtime error
+}
+
+