Remove merge assert in block calculation (#2489)

Fixes #2488

* Validator doesn't identify back-edge of the loop, so the merge is
never set
* Construct::blocks() has safe uses of `merge` so the assert can be
removed
* Added a test
diff --git a/source/val/construct.cpp b/source/val/construct.cpp
index 7b0cb2d..e0053ee 100644
--- a/source/val/construct.cpp
+++ b/source/val/construct.cpp
@@ -73,7 +73,6 @@
   auto header = entry_block();
   auto merge = exit_block();
   assert(header);
-  assert(merge);
   int header_depth = function->GetBlockDepth(const_cast<BasicBlock*>(header));
   ConstructBlockSet construct_blocks;
   std::unordered_set<BasicBlock*> corresponding_headers;
diff --git a/test/val/val_cfg_test.cpp b/test/val/val_cfg_test.cpp
index 7e7dae8..8f39a00 100644
--- a/test/val/val_cfg_test.cpp
+++ b/test/val/val_cfg_test.cpp
@@ -2987,6 +2987,39 @@
           "Statically reachable blocks cannot be terminated by OpUnreachable"));
 }
 
+TEST_F(ValidateCFG, UnreachableLoopBadBackedge) {
+  const std::string text = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %2 "main"
+OpExecutionMode %2 OriginUpperLeft
+%4 = OpTypeVoid
+%5 = OpTypeFunction %4
+%8 = OpTypeBool
+%13 = OpConstantTrue %8
+%2 = OpFunction %4 None %5
+%14 = OpLabel
+OpSelectionMerge %15 None
+OpBranchConditional %13 %15 %15
+%16 = OpLabel
+OpLoopMerge %17 %18 None
+OpBranch %17
+%18 = OpLabel
+OpBranch %17
+%17 = OpLabel
+OpBranch %15
+%15 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  // The back-edge in this test is bad, but the validator fails to identify it
+  // because it is in an entirely unreachable section of code. Prior to #2488
+  // this code failed an assert in Construct::blocks().
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
 TEST_F(ValidateCFG, OneContinueTwoBackedges) {
   const std::string text = R"(
 OpCapability Shader