validation: Fix continue-bypasses-decl check

An expression that is inside an if-statement condition does not have a
"current block", which is what we were using to see if the usage was
inside a continuing block. Use the current statement to find the
containing block instead.

Fixed: chromium:1251664
Change-Id: Icc808ca1cf6a1b51757da8303901fa5ecb693e83
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/65520
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index ba66017..14f5abb 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -2971,12 +2971,12 @@
     var->users.push_back(expr);
     set_referenced_from_function_if_needed(var, true);
 
-    if (current_block_) {
+    if (current_statement_) {
       // If identifier is part of a loop continuing block, make sure it
       // doesn't refer to a variable that is bypassed by a continue statement
       // in the loop's body block.
       if (auto* continuing_block =
-              current_block_
+              current_statement_
                   ->FindFirstParent<sem::LoopContinuingBlockStatement>()) {
         auto* loop_block =
             continuing_block->FindFirstParent<sem::LoopBlockStatement>();
diff --git a/src/resolver/validation_test.cc b/src/resolver/validation_test.cc
index 06cc2bb..1ee8f6f 100644
--- a/src/resolver/validation_test.cc
+++ b/src/resolver/validation_test.cc
@@ -616,6 +616,36 @@
 }
 
 TEST_F(ResolverValidationTest,
+       Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageOutsideBlock) {
+  // loop  {
+  //     if (true) {
+  //         continue; // bypasses z decl (if we reach here)
+  //     }
+  //     var z : i32;
+  //     continuing {
+  //         // Must fail even if z is used in an expression that isn't
+  //         // directly contained inside a block.
+  //         if (z < 2) {
+  //         }
+  //     }
+  // }
+
+  auto error_loc = Source{Source::Location{12, 34}};
+  auto* body = Block(If(Expr(true), Block(create<ast::ContinueStatement>())),
+                     Decl(Var("z", ty.i32(), ast::StorageClass::kNone)));
+  auto* compare = create<ast::BinaryExpression>(ast::BinaryOp::kLessThan,
+                                                Expr(error_loc, "z"), Expr(2));
+  auto* continuing = Block(If(compare, Block()));
+  auto* loop_stmt = Loop(body, continuing);
+  WrapInFunction(loop_stmt);
+
+  EXPECT_FALSE(r()->Resolve()) << r()->error();
+  EXPECT_EQ(r()->error(),
+            "12:34 error: continue statement bypasses declaration of 'z' in "
+            "continuing block");
+}
+
+TEST_F(ResolverValidationTest,
        Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuingLoop) {
   // loop  {
   //     if (true) {