Fix continue construct for single block loops (#4277)

Fixes https://crbug.com/tint/793

* When a loop has an empty loop construct, the loop construct and
  continue construct share the same header so don't disallow the loop
  header for the continue construct
diff --git a/source/val/construct.cpp b/source/val/construct.cpp
index 733856c..5300869 100644
--- a/source/val/construct.cpp
+++ b/source/val/construct.cpp
@@ -78,7 +78,12 @@
   ConstructBlockSet construct_blocks;
   std::unordered_set<BasicBlock*> corresponding_headers;
   for (auto& other : corresponding_constructs()) {
-    corresponding_headers.insert(other->entry_block());
+    // The corresponding header can be the same block as this construct's
+    // header for loops with no loop construct. In those cases, don't add the
+    // loop header as it prevents finding any blocks in the construct.
+    if (type() != ConstructType::kContinue || other->entry_block() != header) {
+      corresponding_headers.insert(other->entry_block());
+    }
   }
   std::vector<BasicBlock*> stack;
   stack.push_back(const_cast<BasicBlock*>(header));
diff --git a/test/val/val_cfg_test.cpp b/test/val/val_cfg_test.cpp
index 9715a5a..6ae2ee6 100644
--- a/test/val/val_cfg_test.cpp
+++ b/test/val/val_cfg_test.cpp
@@ -4364,6 +4364,41 @@
               HasSubstr("OpPhi must not have void result type"));
 }
 
+TEST_F(ValidateCFG, InvalidExitSingleBlockLoop) {
+  const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+OpName %5 "BAD"
+%void = OpTypeVoid
+%bool = OpTypeBool
+%undef = OpUndef %bool
+%void_fn = OpTypeFunction %void
+%fn = OpFunction %void None %void_fn
+%1 = OpLabel
+OpBranch %2
+%2 = OpLabel
+OpLoopMerge %3 %4 None
+OpBranchConditional %undef %3 %5
+%5 = OpLabel
+OpLoopMerge %6 %5 None
+OpBranchConditional %undef %5 %4
+%6 = OpLabel
+OpReturn
+%4 = OpLabel
+OpBranch %2
+%3 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("block <ID> 1[%BAD] exits the continue headed by <ID> "
+                        "1[%BAD], but not via a structured exit"));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools