[dart2js] Fix labeled jump target resolution in SSA builder
When generating SSA jump instructions (HContinue and HBreak) for AST break statements, ensure that we only select labels from the target's label list that are explicitly marked as valid continue (isContinueTarget) or break (isBreakTarget) targets. Previously, handler.labels.first was selected indiscriminately if non-empty, which caused unlabeled continue statements inside loops that had an outer break label to incorrectly generate labeled continue jumps targeting the break label. Fixes: https://github.com/dart-lang/sdk/issues/63456 Change-Id: Ic497776141a192edb0930f4585cdaae2feecb3d5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/510280 Commit-Queue: Nate Biggs <natebiggs@google.com> Reviewed-by: Stephen Adams <sra@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
31b6c9f0d2
commit
6282b35c4c
@@ -3457,14 +3457,28 @@ class KernelSsaGraphBuilder extends ir.VisitorDefault<void>
|
||||
JumpHandler handler = jumpTargets[target]!;
|
||||
final sourceInformation = _sourceInformationBuilder.buildGoto(node);
|
||||
if (_localsMap.generateContinueForBreak(node)) {
|
||||
if (handler.labels.isNotEmpty) {
|
||||
handler.generateContinue(sourceInformation, handler.labels.first);
|
||||
LabelDefinition? continueLabel;
|
||||
for (final label in handler.labels) {
|
||||
if (label.isContinueTarget) {
|
||||
continueLabel = label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (continueLabel != null) {
|
||||
handler.generateContinue(sourceInformation, continueLabel);
|
||||
} else {
|
||||
handler.generateContinue(sourceInformation);
|
||||
}
|
||||
} else {
|
||||
if (handler.labels.isNotEmpty) {
|
||||
handler.generateBreak(sourceInformation, handler.labels.first);
|
||||
LabelDefinition? breakLabel;
|
||||
for (final label in handler.labels) {
|
||||
if (label.isBreakTarget) {
|
||||
breakLabel = label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (breakLabel != null) {
|
||||
handler.generateBreak(sourceInformation, breakLabel);
|
||||
} else {
|
||||
handler.generateBreak(sourceInformation);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2026, 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 'package:expect/expect.dart';
|
||||
|
||||
@pragma('dart2js:never-inline')
|
||||
List<List<int>> getPolys() => [
|
||||
[1, 3],
|
||||
[3, 4],
|
||||
[5],
|
||||
];
|
||||
|
||||
@pragma('dart2js:prefer-inline')
|
||||
int nextP(int p) {
|
||||
if (p < 0) print(p);
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
void main() {
|
||||
var polys = getPolys();
|
||||
int count = 0;
|
||||
for (int iter = 0; iter < 2; iter++) {
|
||||
bool removedAny = false;
|
||||
outer:
|
||||
for (int p = 0; p < polys.length; p = nextP(p)) {
|
||||
final poly = polys[p];
|
||||
if (poly.length <= 1) continue outer;
|
||||
for (int i = 0; i < poly.length; i++) {
|
||||
if (poly[i] == 2) {
|
||||
removedAny = true;
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
Expect.equals(2, count);
|
||||
}
|
||||
Reference in New Issue
Block a user