Recognize more non-fallthrough cases in switch/case

RemoveSwitchFallThrough now treats cases where break; or return; is
nested inside a block as non-fallthrough to avoid unnecessary
duplication of code. For example, the case 1 below would previously
get treated as fall-through:

switch(foo)
{
    case 1:
    {
        break;
    }
    default:
        break;
}

Now RemoveSwitchFallThrough doesn't do anything to this code.

BUG=chromium:772695
TEST=angle_end2end_tests

Change-Id: Iafab6d8b05c63bcdb5f54834dbc1f41192c31dd4
Reviewed-on: https://chromium-review.googlesource.com/709197
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/RemoveSwitchFallThrough.cpp b/src/compiler/translator/RemoveSwitchFallThrough.cpp
index b4a2468..10da1df 100644
--- a/src/compiler/translator/RemoveSwitchFallThrough.cpp
+++ b/src/compiler/translator/RemoveSwitchFallThrough.cpp
@@ -203,12 +203,29 @@
     return false;
 }
 
+bool DoesBlockAlwaysBreak(TIntermBlock *node)
+{
+    if (node->getSequence()->empty())
+    {
+        return false;
+    }
+
+    TIntermBlock *lastStatementAsBlock = node->getSequence()->back()->getAsBlock();
+    if (lastStatementAsBlock)
+    {
+        return DoesBlockAlwaysBreak(lastStatementAsBlock);
+    }
+
+    TIntermBranch *lastStatementAsBranch = node->getSequence()->back()->getAsBranchNode();
+    return lastStatementAsBranch != nullptr;
+}
+
 bool RemoveSwitchFallThroughTraverser::visitBlock(Visit, TIntermBlock *node)
 {
     if (node != mStatementList)
     {
         mPreviousCase->getSequence()->push_back(node);
-        mLastStatementWasBreak = false;
+        mLastStatementWasBreak = DoesBlockAlwaysBreak(node);
         return false;
     }
     return true;