translator: Reject shaders that use both FragColor+FragData.

We checked this at link time in the D3D back-end, but this
restriction applies to all shaders.

TEST=dEQP-GLES2.functional.shaders.fragdata.*
BUG=angleproject:995
BUG=478572

Change-Id: I99111cc6aa05b9352693f9c3b5bc70d56c9842d4
Reviewed-on: https://chromium-review.googlesource.com/269846
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 784032d..a9e9516 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -1049,6 +1049,27 @@
         {
             recover();
         }
+
+        // Reject shaders using both gl_FragData and gl_FragColor
+        TQualifier qualifier = variable->getType().getQualifier();
+        if (qualifier == EvqFragData)
+        {
+            mUsesFragData = true;
+        }
+        else if (qualifier == EvqFragColor)
+        {
+            mUsesFragColor = true;
+        }
+
+        // This validation is not quite correct - it's only an error to write to
+        // both FragData and FragColor. For simplicity, and because users shouldn't
+        // be rewarded for reading from undefined varaibles, return an error
+        // if they are both referenced, rather than assigned.
+        if (mUsesFragData && mUsesFragColor)
+        {
+            error(location, "cannot use both gl_FragData and gl_FragColor", name->c_str());
+            recover();
+        }
     }
 
     if (!variable)
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index d328e9a..1c37e1a 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -57,7 +57,9 @@
           mDirectiveHandler(ext, mDiagnostics, mShaderVersion, debugShaderPrecisionSupported),
           mPreprocessor(&mDiagnostics, &mDirectiveHandler),
           mScanner(nullptr),
-          mDeferredSingleDeclarationErrorCheck(false)
+          mDeferredSingleDeclarationErrorCheck(false),
+          mUsesFragData(false),
+          mUsesFragColor(false)
     {
     }
 
@@ -74,6 +76,7 @@
                const char *extraInfo="");
     void warning(const TSourceLoc &loc, const char *reason, const char *token,
                  const char *extraInfo="");
+
     void recover();
     TIntermNode *getTreeRoot() const { return mTreeRoot; }
     void setTreeRoot(TIntermNode *treeRoot) { mTreeRoot = treeRoot; }
@@ -341,6 +344,8 @@
     TDirectiveHandler mDirectiveHandler;
     pp::Preprocessor mPreprocessor;
     void *mScanner;
+    bool mUsesFragData; // track if we are using both gl_FragData and gl_FragColor
+    bool mUsesFragColor;
 };
 
 int PaParseStrings(
diff --git a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
index b2c24d0..beb6685 100644
--- a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
+++ b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
@@ -757,11 +757,8 @@
     bool usesPointSize = vertexShader->mUsesPointSize;
     bool useInstancedPointSpriteEmulation = usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
 
-    if (usesFragColor && usesFragData)
-    {
-        infoLog << "Cannot use both gl_FragColor and gl_FragData in the same fragment shader.";
-        return false;
-    }
+    // Validation done in the compiler
+    ASSERT(!usesFragColor || !usesFragData);
 
     // Write the HLSL input/output declarations
     const int shaderModel = mRenderer->getMajorShaderModel();
diff --git a/src/tests/compiler_tests/MalformedShader_test.cpp b/src/tests/compiler_tests/MalformedShader_test.cpp
index f5fa4e9..a49167ad 100644
--- a/src/tests/compiler_tests/MalformedShader_test.cpp
+++ b/src/tests/compiler_tests/MalformedShader_test.cpp
@@ -545,3 +545,20 @@
         FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
     }
 }
+
+// Statically assigning to both gl_FragData and gl_FragColor is forbidden (ESSL 1.00 section 7.2)
+TEST_F(MalformedShaderTest, WriteBothFragDataAndFragColor)
+{
+    const std::string &shaderString =
+        "precision mediump float;\n"
+        "void foo() {\n"
+        "   gl_FragData[0].a++;\n"
+        "}\n"
+        "void main() {\n"
+        "   gl_FragColor.x += 0.0;\n"
+        "}\n";
+    if (compile(shaderString))
+    {
+        FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
+    }
+}