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