Fix switch statement validation corner cases

The grammar needs to generate AST nodes even for no-op statements,
since they might be the last statement in a switch statement that is
required for switch statement validity. Change the grammar to generate
nodes from empty blocks and empty declarations.

We also need to do some further processing of the AST. This is because
PruneEmptyDeclarations will still remove empty declarations, and at
least the NVIDIA driver GLSL compiler doesn't accept some types of
no-op statements as the last statement inside a switch statement. So
after parsing has finished we do rudimentary dead code elimination to
remove dead cases from the end of switch statements.

BUG=angleproject:2181
TEST=angle_unittests

Change-Id: I586f2e4a3ac2171e65f1f0ccb7a7de220e3cc225
Reviewed-on: https://chromium-review.googlesource.com/712574
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 99f46b2..d89f3d1 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -29,6 +29,7 @@
 #include "compiler/translator/RegenerateStructNames.h"
 #include "compiler/translator/RemoveArrayLengthMethod.h"
 #include "compiler/translator/RemoveInvariantDeclaration.h"
+#include "compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h"
 #include "compiler/translator/RemovePow.h"
 #include "compiler/translator/RewriteDoWhile.h"
 #include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
@@ -374,6 +375,20 @@
         if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
             success = limitExpressionComplexity(root);
 
+        // Prune empty declarations to work around driver bugs and to keep declaration output
+        // simple. We want to do this before most other operations since TIntermDeclaration nodes
+        // without any children are tricky to work with.
+        if (success)
+            PruneEmptyDeclarations(root);
+
+        // In case the last case inside a switch statement is a certain type of no-op, GLSL
+        // compilers in drivers may not accept it. In this case we clean up the dead code from the
+        // end of switch statements. This is also required because PruneEmptyDeclarations may have
+        // left switch statements that only contained an empty declaration inside the final case in
+        // an invalid state. Relies on that PruneEmptyDeclarations has already been run.
+        if (success)
+            RemoveNoOpCasesFromEndOfSwitchStatements(root, &symbolTable);
+
         // Create the function DAG and check there is no recursion
         if (success)
             success = initCallDag(root);
@@ -392,11 +407,6 @@
         if (success && !(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS))
             success = pruneUnusedFunctions(root);
 
-        // Prune empty declarations to work around driver bugs and to keep declaration output
-        // simple.
-        if (success)
-            PruneEmptyDeclarations(root);
-
         if (success && shaderVersion >= 310)
         {
             success = ValidateVaryingLocations(root, &mDiagnostics);