Fix switch/case last case validation for ESSL 3.10

No statement should be required after the last case label of a switch
statement in ESSL 3.10. The validation is still kept for ESSL 3.00 for
dEQP compatibility. If the dEQP tests are changed in the future, we
might consider just issuing a warning regardless of shader version.

BUG=angleproject:2189
TEST=angle_unittests

Change-Id: Ic53e71e0176668a7dbffa315712885846e217f03
Reviewed-on: https://chromium-review.googlesource.com/727802
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/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index e5f9f59..6631e49 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -4640,8 +4640,9 @@
     }
 
     ASSERT(statementList);
-    if (!ValidateSwitchStatementList(switchType, mDiagnostics, statementList, loc))
+    if (!ValidateSwitchStatementList(switchType, mShaderVersion, mDiagnostics, statementList, loc))
     {
+        ASSERT(mDiagnostics->numErrors() > 0);
         return nullptr;
     }
 
diff --git a/src/compiler/translator/ValidateSwitch.cpp b/src/compiler/translator/ValidateSwitch.cpp
index bc9ba34..9f7a264 100644
--- a/src/compiler/translator/ValidateSwitch.cpp
+++ b/src/compiler/translator/ValidateSwitch.cpp
@@ -19,6 +19,7 @@
 {
   public:
     static bool validate(TBasicType switchType,
+                         int shaderVersion,
                          TDiagnostics *diagnostics,
                          TIntermBlock *statementList,
                          const TSourceLoc &loc);
@@ -39,11 +40,12 @@
     bool visitBranch(Visit, TIntermBranch *) override;
 
   private:
-    ValidateSwitch(TBasicType switchType, TDiagnostics *context);
+    ValidateSwitch(TBasicType switchType, int shaderVersion, TDiagnostics *context);
 
     bool validateInternal(const TSourceLoc &loc);
 
     TBasicType mSwitchType;
+    int mShaderVersion;
     TDiagnostics *mDiagnostics;
     bool mCaseTypeMismatch;
     bool mFirstCaseFound;
@@ -58,19 +60,21 @@
 };
 
 bool ValidateSwitch::validate(TBasicType switchType,
+                              int shaderVersion,
                               TDiagnostics *diagnostics,
                               TIntermBlock *statementList,
                               const TSourceLoc &loc)
 {
-    ValidateSwitch validate(switchType, diagnostics);
+    ValidateSwitch validate(switchType, shaderVersion, diagnostics);
     ASSERT(statementList);
     statementList->traverse(&validate);
     return validate.validateInternal(loc);
 }
 
-ValidateSwitch::ValidateSwitch(TBasicType switchType, TDiagnostics *diagnostics)
+ValidateSwitch::ValidateSwitch(TBasicType switchType, int shaderVersion, TDiagnostics *diagnostics)
     : TIntermTraverser(true, false, true),
       mSwitchType(switchType),
+      mShaderVersion(shaderVersion),
       mDiagnostics(diagnostics),
       mCaseTypeMismatch(false),
       mFirstCaseFound(false),
@@ -277,24 +281,39 @@
     {
         mDiagnostics->error(loc, "statement before the first label", "switch");
     }
+    bool lastStatementWasCaseError = false;
     if (mLastStatementWasCase)
     {
-        mDiagnostics->error(
-            loc, "no statement between the last label and the end of the switch statement",
-            "switch");
+        if (mShaderVersion == 300)
+        {
+            lastStatementWasCaseError = true;
+            // This error has been proposed to be made optional in GLSL ES 3.00, but dEQP tests
+            // still require it.
+            mDiagnostics->error(
+                loc, "no statement between the last label and the end of the switch statement",
+                "switch");
+        }
+        else
+        {
+            // The error has been removed from GLSL ES 3.10.
+            mDiagnostics->warning(
+                loc, "no statement between the last label and the end of the switch statement",
+                "switch");
+        }
     }
-    return !mStatementBeforeCase && !mLastStatementWasCase && !mCaseInsideControlFlow &&
+    return !mStatementBeforeCase && !lastStatementWasCaseError && !mCaseInsideControlFlow &&
            !mCaseTypeMismatch && mDefaultCount <= 1 && !mDuplicateCases;
 }
 
 }  // anonymous namespace
 
 bool ValidateSwitchStatementList(TBasicType switchType,
+                                 int shaderVersion,
                                  TDiagnostics *diagnostics,
                                  TIntermBlock *statementList,
                                  const TSourceLoc &loc)
 {
-    return ValidateSwitch::validate(switchType, diagnostics, statementList, loc);
+    return ValidateSwitch::validate(switchType, shaderVersion, diagnostics, statementList, loc);
 }
 
 }  // namespace sh
diff --git a/src/compiler/translator/ValidateSwitch.h b/src/compiler/translator/ValidateSwitch.h
index 757820a..2d2dd70 100644
--- a/src/compiler/translator/ValidateSwitch.h
+++ b/src/compiler/translator/ValidateSwitch.h
@@ -18,6 +18,7 @@
 // Check for errors and output error messages on the context.
 // Returns true if there are no errors.
 bool ValidateSwitchStatementList(TBasicType switchType,
+                                 int shaderVersion,
                                  TDiagnostics *diagnostics,
                                  TIntermBlock *statementList,
                                  const TSourceLoc &loc);
diff --git a/src/tests/compiler_tests/ShaderValidation_test.cpp b/src/tests/compiler_tests/ShaderValidation_test.cpp
index 0f91fe6..617d76f 100644
--- a/src/tests/compiler_tests/ShaderValidation_test.cpp
+++ b/src/tests/compiler_tests/ShaderValidation_test.cpp
@@ -5063,3 +5063,27 @@
         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
     }
 }
+
+// Test that nothing is needed after the final case in a switch statement in ESSL 3.10.
+TEST_F(FragmentShaderValidationTest, SwitchFinalCaseEmptyESSL310)
+{
+    const std::string &shaderString =
+        R"(#version 310 es
+
+        precision mediump float;
+        uniform int i;
+        void main()
+        {
+            switch (i)
+            {
+                case 0:
+                    break;
+                default:
+            }
+        })";
+
+    if (!compile(shaderString))
+    {
+        FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
+    }
+}