Edit

kc3-lang/angle/src/tests/compiler_tests/MalformedShader_test.cpp

Branch :

  • Show log

    Commit

  • Author : Olli Etuaho
    Date : 2016-12-19 19:53:29
    Hash : 72fc5547
    Message : Add a ShaderCompileTreeTest base class to use in compiler tests The test class provides facilities for parsing test shader source into an AST and determining compile status. Compilation flags change for some of the tests, but this should only have a minor effect on code coverage - mostly affecting non-core parts such as intermediate output. BUG=angleproject:1673 TEST=angle_unittests Change-Id: I7d0900ef490e021272a27c4b0c938bfee02abf39 Reviewed-on: https://chromium-review.googlesource.com/422367 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>

  • src/tests/compiler_tests/MalformedShader_test.cpp
  • //
    // Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // MalformedShader_test.cpp:
    //   Tests that malformed shaders fail compilation.
    //
    
    #include "angle_gl.h"
    #include "gtest/gtest.h"
    #include "GLSLANG/ShaderLang.h"
    #include "compiler/translator/TranslatorESSL.h"
    #include "tests/test_utils/ShaderCompileTreeTest.h"
    
    using namespace sh;
    
    class MalformedShaderTest : public ShaderCompileTreeTest
    {
      public:
        MalformedShaderTest() {}
      protected:
        ::GLenum getShaderType() const override { return GL_FRAGMENT_SHADER; }
        ShShaderSpec getShaderSpec() const override { return SH_GLES3_SPEC; }
    };
    
    class MalformedVertexShaderTest : public ShaderCompileTreeTest
    {
      public:
        MalformedVertexShaderTest() {}
    
      protected:
        ::GLenum getShaderType() const override { return GL_VERTEX_SHADER; }
        ShShaderSpec getShaderSpec() const override { return SH_GLES3_SPEC; }
    };
    
    class MalformedWebGL2ShaderTest : public ShaderCompileTreeTest
    {
      public:
        MalformedWebGL2ShaderTest() {}
    
      protected:
        ::GLenum getShaderType() const override { return GL_FRAGMENT_SHADER; }
        ShShaderSpec getShaderSpec() const override { return SH_WEBGL2_SPEC; }
    };
    
    class MalformedWebGL1ShaderTest : public ShaderCompileTreeTest
    {
      public:
        MalformedWebGL1ShaderTest() {}
    
      protected:
        ::GLenum getShaderType() const override { return GL_FRAGMENT_SHADER; }
        ShShaderSpec getShaderSpec() const override { return SH_WEBGL_SPEC; }
    };
    
    class MalformedVertexShaderGLES31Test : public ShaderCompileTreeTest
    {
      public:
        MalformedVertexShaderGLES31Test() {}
    
      private:
        ::GLenum getShaderType() const override { return GL_VERTEX_SHADER; }
        ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; }
    };
    
    class MalformedFragmentShaderGLES31Test : public ShaderCompileTreeTest
    {
      public:
        MalformedFragmentShaderGLES31Test() {}
    
      private:
        ::GLenum getShaderType() const override { return GL_FRAGMENT_SHADER; }
        ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; }
    };
    
    class MalformedComputeShaderTest : public ShaderCompileTreeTest
    {
      public:
        MalformedComputeShaderTest() {}
    
      private:
        ::GLenum getShaderType() const override { return GL_COMPUTE_SHADER; }
        ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; }
    };
    
    // This is a test for a bug that used to exist in ANGLE:
    // Calling a function with all parameters missing should not succeed.
    TEST_F(MalformedShaderTest, FunctionParameterMismatch)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "float fun(float a) {\n"
            "   return a * 2.0;\n"
            "}\n"
            "void main() {\n"
            "   float ff = fun();\n"
            "   gl_FragColor = vec4(ff);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Functions can't be redeclared as variables in the same scope (ESSL 1.00 section 4.2.7)
    TEST_F(MalformedShaderTest, RedeclaringFunctionAsVariable)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "float fun(float a) {\n"
            "   return a * 2.0;\n"
            "}\n"
            "float fun;\n"
            "void main() {\n"
            "   gl_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Functions can't be redeclared as structs in the same scope (ESSL 1.00 section 4.2.7)
    TEST_F(MalformedShaderTest, RedeclaringFunctionAsStruct)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "float fun(float a) {\n"
            "   return a * 2.0;\n"
            "}\n"
            "struct fun { float a; };\n"
            "void main() {\n"
            "   gl_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Functions can't be redeclared with different qualifiers (ESSL 1.00 section 6.1.0)
    TEST_F(MalformedShaderTest, RedeclaringFunctionWithDifferentQualifiers)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "float fun(out float a);\n"
            "float fun(float a) {\n"
            "   return a * 2.0;\n"
            "}\n"
            "void main() {\n"
            "   gl_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Assignment and equality are undefined for structures containing arrays (ESSL 1.00 section 5.7)
    TEST_F(MalformedShaderTest, CompareStructsContainingArrays)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "struct s { float a[3]; };\n"
            "void main() {\n"
            "   s a;\n"
            "   s b;\n"
            "   bool c = (a == b);\n"
            "   gl_FragColor = vec4(c ? 1.0 : 0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Assignment and equality are undefined for structures containing arrays (ESSL 1.00 section 5.7)
    TEST_F(MalformedShaderTest, AssignStructsContainingArrays)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "struct s { float a[3]; };\n"
            "void main() {\n"
            "   s a;\n"
            "   s b;\n"
            "   b.a[0] = 0.0;\n"
            "   a = b;\n"
            "   gl_FragColor = vec4(a.a[0]);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Assignment and equality are undefined for structures containing samplers (ESSL 1.00 sections 5.7 and 5.9)
    TEST_F(MalformedShaderTest, CompareStructsContainingSamplers)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "struct s { sampler2D foo; };\n"
            "uniform s a;\n"
            "uniform s b;\n"
            "void main() {\n"
            "   bool c = (a == b);\n"
            "   gl_FragColor = vec4(c ? 1.0 : 0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Samplers are not allowed as l-values (ESSL 3.00 section 4.1.7), our interpretation is that this
    // extends to structs containing samplers. ESSL 1.00 spec is clearer about this.
    TEST_F(MalformedShaderTest, AssignStructsContainingSamplers)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "struct s { sampler2D foo; };\n"
            "uniform s a;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   s b;\n"
            "   b = a;\n"
            "   my_FragColor = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // This is a regression test for a particular bug that was in ANGLE.
    // It also verifies that ESSL3 functionality doesn't leak to ESSL1.
    TEST_F(MalformedShaderTest, ArrayWithNoSizeInInitializerList)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "void main() {\n"
            "   float a[2], b[];\n"
            "   gl_FragColor = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Const variables need an initializer.
    TEST_F(MalformedShaderTest, ConstVarNotInitialized)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   const float a;\n"
            "   my_FragColor = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Const variables need an initializer. In ESSL1 const structs containing
    // arrays are not allowed at all since it's impossible to initialize them.
    // Even though this test is for ESSL3 the only thing that's critical for
    // ESSL1 is the non-initialization check that's used for both language versions.
    // Whether ESSL1 compilation generates the most helpful error messages is a
    // secondary concern.
    TEST_F(MalformedShaderTest, ConstStructNotInitialized)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "struct S {\n"
            "   float a[3];\n"
            "};\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   const S b;\n"
            "   my_FragColor = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Const variables need an initializer. In ESSL1 const arrays are not allowed
    // at all since it's impossible to initialize them.
    // Even though this test is for ESSL3 the only thing that's critical for
    // ESSL1 is the non-initialization check that's used for both language versions.
    // Whether ESSL1 compilation generates the most helpful error messages is a
    // secondary concern.
    TEST_F(MalformedShaderTest, ConstArrayNotInitialized)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   const float a[3];\n"
            "   my_FragColor = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Block layout qualifiers can't be used on non-block uniforms (ESSL 3.00 section 4.3.8.3)
    TEST_F(MalformedShaderTest, BlockLayoutQualifierOnRegularUniform)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "layout(packed) uniform mat2 x;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   my_FragColor = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Block layout qualifiers can't be used on non-block uniforms (ESSL 3.00 section 4.3.8.3)
    TEST_F(MalformedShaderTest, BlockLayoutQualifierOnUniformWithEmptyDecl)
    {
        // Yes, the comma in the declaration below is not a typo.
        // Empty declarations are allowed in GLSL.
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "layout(packed) uniform mat2, x;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   my_FragColor = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Arrays of arrays are not allowed (ESSL 3.00 section 4.1.9)
    TEST_F(MalformedShaderTest, ArraysOfArrays1)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   float[5] a[3];\n"
            "   my_FragColor = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Arrays of arrays are not allowed (ESSL 3.00 section 4.1.9)
    TEST_F(MalformedShaderTest, ArraysOfArrays2)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   float[2] a, b[3];\n"
            "   my_FragColor = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Implicitly sized arrays need to be initialized (ESSL 3.00 section 4.1.9)
    TEST_F(MalformedShaderTest, UninitializedImplicitArraySize)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   float[] a;\n"
            "   my_FragColor = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // An operator can only form a constant expression if all the operands are constant expressions
    // - even operands of ternary operator that are never evaluated. (ESSL 3.00 section 4.3.3)
    TEST_F(MalformedShaderTest, TernaryOperatorNotConstantExpression)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "uniform bool u;\n"
            "void main() {\n"
            "   const bool a = true ? true : u;\n"
            "   my_FragColor = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Ternary operator can't operate on arrays (ESSL 3.00 section 5.7)
    TEST_F(MalformedShaderTest, TernaryOperatorOnArrays)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   float[1] a = float[1](0.0);\n"
            "   float[1] b = float[1](1.0);\n"
            "   float[1] c = true ? a : b;\n"
            "   my_FragColor = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Ternary operator can't operate on structs (ESSL 3.00 section 5.7)
    TEST_F(MalformedShaderTest, TernaryOperatorOnStructs)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "struct S { float foo; };\n"
            "void main() {\n"
            "   S a = S(0.0);\n"
            "   S b = S(1.0);\n"
            "   S c = true ? a : b;\n"
            "   my_FragColor = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Array length() returns a constant signed integral expression (ESSL 3.00 section 4.1.9)
    // Assigning it to unsigned should result in an error.
    TEST_F(MalformedShaderTest, AssignArrayLengthToUnsigned)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   int[1] arr;\n"
            "   uint l = arr.length();\n"
            "   my_FragColor = vec4(float(l));\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Global variable initializers need to be constant expressions (ESSL 1.00 section 4.3)
    // Initializing with a varying should be an error.
    TEST_F(MalformedShaderTest, AssignVaryingToGlobal)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "varying float a;\n"
            "float b = a * 2.0;\n"
            "void main() {\n"
            "   gl_FragColor = vec4(b);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Global variable initializers need to be constant expressions (ESSL 3.00 section 4.3)
    // Initializing with an uniform should be an error.
    TEST_F(MalformedShaderTest, AssignUniformToGlobalESSL3)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "uniform float a;\n"
            "float b = a * 2.0;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   my_FragColor = vec4(b);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Global variable initializers need to be constant expressions (ESSL 1.00 section 4.3)
    // Initializing with an uniform should generate a warning
    // (we don't generate an error on ESSL 1.00 because of legacy compatibility)
    TEST_F(MalformedShaderTest, AssignUniformToGlobalESSL1)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "uniform float a;\n"
            "float b = a * 2.0;\n"
            "void main() {\n"
            "   gl_FragColor = vec4(b);\n"
            "}\n";
        if (compile(shaderString))
        {
            if (!hasWarning())
            {
                FAIL() << "Shader compilation succeeded without warnings, expecting warning " << mInfoLog;
            }
        }
        else
        {
            FAIL() << "Shader compilation failed, expecting success with warning " << mInfoLog;
        }
    }
    
    // Global variable initializers need to be constant expressions (ESSL 1.00 section 4.3)
    // Initializing with an user-defined function call should be an error.
    TEST_F(MalformedShaderTest, AssignFunctionCallToGlobal)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "float foo() { return 1.0; }\n"
            "float b = foo();\n"
            "void main() {\n"
            "   gl_FragColor = vec4(b);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Global variable initializers need to be constant expressions (ESSL 1.00 section 4.3)
    // Initializing with an assignment to another global should be an error.
    TEST_F(MalformedShaderTest, AssignAssignmentToGlobal)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "float c = 1.0;\n"
            "float b = (c = 0.0);\n"
            "void main() {\n"
            "   gl_FragColor = vec4(b);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Global variable initializers need to be constant expressions (ESSL 1.00 section 4.3)
    // Initializing with incrementing another global should be an error.
    TEST_F(MalformedShaderTest, AssignIncrementToGlobal)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "float c = 1.0;\n"
            "float b = (c++);\n"
            "void main() {\n"
            "   gl_FragColor = vec4(b);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Global variable initializers need to be constant expressions (ESSL 1.00 section 4.3)
    // Initializing with a texture lookup function call should be an error.
    TEST_F(MalformedShaderTest, AssignTexture2DToGlobal)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "uniform mediump sampler2D s;\n"
            "float b = texture2D(s, vec2(0.5, 0.5)).x;\n"
            "void main() {\n"
            "   gl_FragColor = vec4(b);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Global variable initializers need to be constant expressions (ESSL 3.00 section 4.3)
    // Initializing with a non-constant global should be an error.
    TEST_F(MalformedShaderTest, AssignNonConstGlobalToGlobal)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "float a = 1.0;\n"
            "float b = a * 2.0;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   my_FragColor = vec4(b);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Global variable initializers need to be constant expressions (ESSL 3.00 section 4.3)
    // Initializing with a constant global should be fine.
    TEST_F(MalformedShaderTest, AssignConstGlobalToGlobal)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "const float a = 1.0;\n"
            "float b = a * 2.0;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   my_FragColor = vec4(b);\n"
            "}\n";
        if (!compile(shaderString))
        {
            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;
        }
    }
    
    // Version directive must be on the first line (ESSL 3.00 section 3.3)
    TEST_F(MalformedShaderTest, VersionOnSecondLine)
    {
        const std::string &shaderString =
            "\n"
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "   my_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Layout qualifier can only appear in global scope (ESSL 3.00 section 4.3.8)
    TEST_F(MalformedShaderTest, LayoutQualifierInCondition)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "uniform vec4 u;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "    int i = 0;\n"
            "    for (int j = 0; layout(location = 0) bool b = false; ++j) {\n"
            "        ++i;\n"
            "    }\n"
            "    my_FragColor = u;\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Layout qualifier can only appear where specified (ESSL 3.00 section 4.3.8)
    TEST_F(MalformedShaderTest, LayoutQualifierInFunctionReturnType)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "uniform vec4 u;\n"
            "out vec4 my_FragColor;\n"
            "layout(location = 0) vec4 foo() {\n"
            "    return u;\n"
            "}\n"
            "void main() {\n"
            "    my_FragColor = foo();\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // If there is more than one output, the location must be specified for all outputs.
    // (ESSL 3.00.04 section 4.3.8.2)
    TEST_F(MalformedShaderTest, TwoOutputsNoLayoutQualifiers)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "uniform vec4 u;\n"
            "out vec4 my_FragColor;\n"
            "out vec4 my_SecondaryFragColor;\n"
            "void main() {\n"
            "    my_FragColor = vec4(1.0);\n"
            "    my_SecondaryFragColor = vec4(0.5);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // (ESSL 3.00.04 section 4.3.8.2)
    TEST_F(MalformedShaderTest, TwoOutputsFirstLayoutQualifier)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "uniform vec4 u;\n"
            "layout(location = 0) out vec4 my_FragColor;\n"
            "out vec4 my_SecondaryFragColor;\n"
            "void main() {\n"
            "    my_FragColor = vec4(1.0);\n"
            "    my_SecondaryFragColor = vec4(0.5);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // (ESSL 3.00.04 section 4.3.8.2)
    TEST_F(MalformedShaderTest, TwoOutputsSecondLayoutQualifier)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "uniform vec4 u;\n"
            "out vec4 my_FragColor;\n"
            "layout(location = 0) out vec4 my_SecondaryFragColor;\n"
            "void main() {\n"
            "    my_FragColor = vec4(1.0);\n"
            "    my_SecondaryFragColor = vec4(0.5);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Uniforms can be arrays (ESSL 3.00 section 4.3.5)
    TEST_F(MalformedShaderTest, UniformArray)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "uniform vec4[2] u;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "    my_FragColor = u[0];\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Fragment shader input variables cannot be arrays of structs (ESSL 3.00 section 4.3.4)
    TEST_F(MalformedShaderTest, FragmentInputArrayOfStructs)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "struct S {\n"
            "    vec4 foo;\n"
            "};\n"
            "in S i[2];\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "    my_FragColor = i[0].foo;\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Vertex shader inputs can't be arrays (ESSL 3.00 section 4.3.4)
    // This test is testing the case where the array brackets are after the variable name, so
    // the arrayness isn't known when the type and qualifiers are initially parsed.
    TEST_F(MalformedVertexShaderTest, VertexShaderInputArray)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "in vec4 i[2];\n"
            "void main() {\n"
            "    gl_Position = i[0];\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Vertex shader inputs can't be arrays (ESSL 3.00 section 4.3.4)
    // This test is testing the case where the array brackets are after the type.
    TEST_F(MalformedVertexShaderTest, VertexShaderInputArrayType)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "in vec4[2] i;\n"
            "void main() {\n"
            "    gl_Position = i[0];\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Fragment shader inputs can't contain booleans (ESSL 3.00 section 4.3.4)
    TEST_F(MalformedShaderTest, FragmentShaderInputStructWithBool)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "struct S {\n"
            "    bool foo;\n"
            "};\n"
            "in S s;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "    my_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Fragment shader inputs without a flat qualifier can't contain integers (ESSL 3.00 section 4.3.4)
    TEST_F(MalformedShaderTest, FragmentShaderInputStructWithInt)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "struct S {\n"
            "    int foo;\n"
            "};\n"
            "in S s;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "    my_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Selecting a field of a vector that's the result of dynamic indexing a constant array should work.
    TEST_F(MalformedShaderTest, ShaderSelectingFieldOfVectorIndexedFromArray)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "uniform int i;\n"
            "void main() {\n"
            "    float f = vec2[1](vec2(0.0, 0.1))[i].x;\n"
            "    my_FragColor = vec4(f);\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Passing an array into a function and then passing a value from that array into another function
    // should work. This is a regression test for a bug where the mangled name of a TType was not
    // properly updated when determining the type resulting from array indexing.
    TEST_F(MalformedShaderTest, ArrayValueFromFunctionParameterAsParameter)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "uniform float u;\n"
            "float foo(float f) {\n"
            "   return f * 2.0;\n"
            "}\n"
            "float bar(float[2] f) {\n"
            "    return foo(f[0]);\n"
            "}\n"
            "void main()\n"
            "{\n"
            "    float arr[2];\n"
            "    arr[0] = u;\n"
            "    gl_FragColor = vec4(bar(arr));\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Test that out-of-range integer literal generates an error in ESSL 3.00.
    TEST_F(MalformedShaderTest, OutOfRangeIntegerLiteral)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "precision highp int;\n"
            "out vec4 my_FragColor;\n"
            "void main() {\n"
            "    my_FragColor = vec4(0x100000000);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that vector field selection from a value taken from an array constructor is accepted as a
    // constant expression.
    TEST_F(MalformedShaderTest, FieldSelectionFromVectorArrayConstructorIsConst)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "    const float f = vec2[1](vec2(0.0, 1.0))[0].x;\n"
            "    my_FragColor = vec4(f);\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Test that structure field selection from a value taken from an array constructor is accepted as a
    // constant expression.
    TEST_F(MalformedShaderTest, FieldSelectionFromStructArrayConstructorIsConst)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "struct S { float member; };\n"
            "void main()\n"
            "{\n"
            "    const float f = S[1](S(0.0))[0].member;\n"
            "    my_FragColor = vec4(f);\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Test that a reference to a const array is accepted as a constant expression.
    TEST_F(MalformedShaderTest, ArraySymbolIsConst)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "    const float[2] arr = float[2](0.0, 1.0);\n"
            "    const float f = arr[0];\n"
            "    my_FragColor = vec4(f);\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Test that using an array constructor in a parameter to a built-in function is accepted as a
    // constant expression.
    TEST_F(MalformedShaderTest, BuiltInFunctionAppliedToArrayConstructorIsConst)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "    const float f = sin(float[2](0.0, 1.0)[0]);\n"
            "    my_FragColor = vec4(f);\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Test that using an array constructor in a parameter to a built-in function is accepted as a
    // constant expression.
    TEST_F(MalformedShaderTest, BuiltInFunctionWithMultipleParametersAppliedToArrayConstructorIsConst)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "    const float f = pow(1.0, float[2](0.0, 1.0)[0]);\n"
            "    my_FragColor = vec4(f);\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Test that using an array constructor in a parameter to a constructor is accepted as a constant
    // expression.
    TEST_F(MalformedShaderTest, ConstructorWithMultipleParametersAppliedToArrayConstructorIsConst)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "    const vec2 f = vec2(1.0, float[2](0.0, 1.0)[0]);\n"
            "    my_FragColor = vec4(f.x);\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Test that using an array constructor in an operand of the ternary selection operator is accepted
    // as a constant expression.
    TEST_F(MalformedShaderTest, TernaryOperatorAppliedToArrayConstructorIsConst)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "    const float f = true ? float[2](0.0, 1.0)[0] : 1.0;\n"
            "    my_FragColor = vec4(f);\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Test that a ternary operator with one unevaluated non-constant operand is not a constant
    // expression.
    TEST_F(MalformedShaderTest, TernaryOperatorNonConstantOperand)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "uniform float u;\n"
            "void main()\n"
            "{\n"
            "    const float f = true ? 1.0 : u;\n"
            "    gl_FragColor = vec4(f);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that a sampler can't be used in constructor argument list
    TEST_F(MalformedShaderTest, SamplerInConstructorArguments)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "uniform sampler2D s;\n"
            "void main()\n"
            "{\n"
            "    vec2 v = vec2(0.0, s);\n"
            "    gl_FragColor = vec4(v, 0.0, 0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that void can't be used in constructor argument list
    TEST_F(MalformedShaderTest, VoidInConstructorArguments)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "void foo() {}\n"
            "void main()\n"
            "{\n"
            "    vec2 v = vec2(0.0, foo());\n"
            "    gl_FragColor = vec4(v, 0.0, 0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that a shader passing a struct into a constructor of array of structs with 1 element works.
    TEST_F(MalformedShaderTest, SingleStructArrayConstructor)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "uniform float u;\n"
            "struct S { float member; };\n"
            "void main()\n"
            "{\n"
            "    S[1] sarr = S[1](S(u));\n"
            "    my_FragColor = vec4(sarr[0].member);\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Test that a shader with empty constructor parameter list is not accepted.
    TEST_F(MalformedShaderTest, EmptyArrayConstructor)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "uniform float u;\n"
            "const float[] f = f[]();\n"
            "void main()\n"
            "{\n"
            "    my_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that indexing fragment outputs with a non-constant expression is forbidden, even if ANGLE
    // is able to constant fold the index expression. ESSL 3.00 section 4.3.6.
    TEST_F(MalformedShaderTest, DynamicallyIndexedFragmentOutput)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "uniform int a;\n"
            "out vec4[2] my_FragData;\n"
            "void main()\n"
            "{\n"
            "    my_FragData[true ? 0 : a] = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that indexing an interface block array with a non-constant expression is forbidden, even if
    // ANGLE is able to constant fold the index expression. ESSL 3.00 section 4.3.7.
    TEST_F(MalformedShaderTest, DynamicallyIndexedInterfaceBlock)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "uniform int a;\n"
            "uniform B\n"
            "{\n"
            "    vec4 f;\n"
            "}\n"
            "blocks[2];\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "    my_FragColor = blocks[true ? 0 : a].f;\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that a shader that uses a struct definition in place of a struct constructor does not
    // compile. See GLSL ES 1.00 section 5.4.3.
    TEST_F(MalformedShaderTest, StructConstructorWithStructDefinition)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "void main()\n"
            "{\n"
            "    struct s { float f; } (0.0);\n"
            "    gl_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that indexing gl_FragData with a non-constant expression is forbidden in WebGL 2.0, even
    // when ANGLE is able to constant fold the index.
    // WebGL 2.0 spec section 'GLSL ES 1.00 Fragment Shader Output'
    TEST_F(MalformedWebGL2ShaderTest, IndexFragDataWithNonConstant)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "void main()\n"
            "{\n"
            "    for (int i = 0; i < 2; ++i) {\n"
            "        gl_FragData[true ? 0 : i] = vec4(0.0);\n"
            "    }\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that a non-constant texture offset is not accepted for textureOffset.
    // ESSL 3.00 section 8.8
    TEST_F(MalformedShaderTest, TextureOffsetNonConst)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "uniform vec3 u_texCoord;\n"
            "uniform mediump sampler3D u_sampler;\n"
            "uniform int x;\n"
            "void main()\n"
            "{\n"
            "   my_FragColor = textureOffset(u_sampler, u_texCoord, ivec3(x, 3, -8));\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that a non-constant texture offset is not accepted for textureProjOffset with bias.
    // ESSL 3.00 section 8.8
    TEST_F(MalformedShaderTest, TextureProjOffsetNonConst)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "uniform vec4 u_texCoord;\n"
            "uniform mediump sampler3D u_sampler;\n"
            "uniform int x;\n"
            "void main()\n"
            "{\n"
            "   my_FragColor = textureProjOffset(u_sampler, u_texCoord, ivec3(x, 3, -8), 0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that an out-of-range texture offset is not accepted.
    // GLES 3.0.4 section 3.8.10 specifies that out-of-range offset has undefined behavior.
    TEST_F(MalformedShaderTest, TextureLodOffsetOutOfRange)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "uniform vec3 u_texCoord;\n"
            "uniform mediump sampler3D u_sampler;\n"
            "void main()\n"
            "{\n"
            "   my_FragColor = textureLodOffset(u_sampler, u_texCoord, 0.0, ivec3(0, 0, 8));\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that default precision qualifier for uint is not accepted.
    // ESSL 3.00.4 section 4.5.4: Only allowed for float, int and sampler types.
    TEST_F(MalformedShaderTest, DefaultPrecisionUint)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "precision mediump uint;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "   my_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that sampler3D needs to be precision qualified.
    // ESSL 3.00.4 section 4.5.4: New ESSL 3.00 sampler types don't have predefined precision.
    TEST_F(MalformedShaderTest, NoPrecisionSampler3D)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "uniform sampler3D s;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "   my_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that using a non-constant expression in a for loop initializer is forbidden in WebGL 1.0,
    // even when ANGLE is able to constant fold the initializer.
    // ESSL 1.00 Appendix A.
    TEST_F(MalformedWebGL1ShaderTest, NonConstantLoopIndex)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "uniform int u;\n"
            "void main()\n"
            "{\n"
            "    for (int i = (true ? 1 : u); i < 5; ++i) {\n"
            "        gl_FragColor = vec4(0.0);\n"
            "    }\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Check that indices that are not integers are rejected.
    // The check should be done even if ESSL 1.00 Appendix A limitations are not applied.
    TEST_F(MalformedShaderTest, NonIntegerIndex)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "void main()\n"
            "{\n"
            "    float f[3];\n"
            "    const float i = 2.0;\n"
            "    gl_FragColor = vec4(f[i]);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // ESSL1 shaders with a duplicate function prototype should be rejected.
    // ESSL 1.00.17 section 4.2.7.
    TEST_F(MalformedShaderTest, DuplicatePrototypeESSL1)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "void foo();\n"
            "void foo();\n"
            "void foo() {}\n"
            "void main()\n"
            "{\n"
            "    gl_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // ESSL3 shaders with a duplicate function prototype should be allowed.
    // ESSL 3.00.4 section 4.2.3.
    TEST_F(MalformedShaderTest, DuplicatePrototypeESSL3)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void foo();\n"
            "void foo();\n"
            "void foo() {}\n"
            "void main()\n"
            "{\n"
            "    my_FragColor = vec4(0.0);\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Shaders with a local function prototype should be rejected.
    // ESSL 3.00.4 section 4.2.4.
    TEST_F(MalformedShaderTest, LocalFunctionPrototype)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "    void foo();\n"
            "    my_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // ESSL 3.00 fragment shaders can not use #pragma STDGL invariant(all).
    // ESSL 3.00.4 section 4.6.1. Does not apply to other versions of ESSL.
    TEST_F(MalformedShaderTest, ESSL300FragmentInvariantAll)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "#pragma STDGL invariant(all)\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "    my_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Built-in functions can be overloaded in ESSL 1.00.
    TEST_F(MalformedShaderTest, ESSL100BuiltInFunctionOverload)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "int sin(int x)\n"
            "{\n"
            "    return int(sin(float(x)));\n"
            "}\n"
            "void main()\n"
            "{\n"
            "   gl_FragColor = vec4(sin(1));"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Built-in functions can not be overloaded in ESSL 3.00.
    TEST_F(MalformedShaderTest, ESSL300BuiltInFunctionOverload)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "int sin(int x)\n"
            "{\n"
            "    return int(sin(float(x)));\n"
            "}\n"
            "void main()\n"
            "{\n"
            "   my_FragColor = vec4(sin(1));"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Multiplying a 4x2 matrix with a 4x2 matrix should not work.
    TEST_F(MalformedShaderTest, CompoundMultiplyMatrixIdenticalNonSquareDimensions)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "   mat4x2 foo;\n"
            "   foo *= mat4x2(4.0);\n"
            "   my_FragColor = vec4(0.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Multiplying a matrix with 2 columns and 4 rows with a 2x2 matrix should work.
    TEST_F(MalformedShaderTest, CompoundMultiplyMatrixValidNonSquareDimensions)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "   mat2x4 foo;\n"
            "   foo *= mat2x2(4.0);\n"
            "   my_FragColor = vec4(0.0);\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Covers a bug where we would set the incorrect result size on an out-of-bounds vector swizzle.
    TEST_F(MalformedShaderTest, OutOfBoundsVectorSwizzle)
    {
        const std::string &shaderString =
            "void main() {\n"
            "   vec2(0).qq;\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Covers a bug where strange preprocessor defines could trigger asserts.
    TEST_F(MalformedShaderTest, DefineWithSemicolon)
    {
        const std::string &shaderString =
            "#define Def; highp\n"
            "uniform Def vec2 a;\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Covers a bug in our parsing of malformed shift preprocessor expressions.
    TEST_F(MalformedShaderTest, LineDirectiveUndefinedShift)
    {
        const std::string &shaderString = "#line x << y";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Covers a bug in our parsing of malformed shift preprocessor expressions.
    TEST_F(MalformedShaderTest, LineDirectiveNegativeShift)
    {
        const std::string &shaderString = "#line x << -1";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // gl_MaxImageUnits is only available in ES 3.1 shaders.
    TEST_F(MalformedShaderTest, MaxImageUnitsInES3Shader)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 myOutput;"
            "void main() {\n"
            "   float ff = float(gl_MaxImageUnits);\n"
            "   myOutput = vec4(ff);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // struct += struct is an invalid operation.
    TEST_F(MalformedShaderTest, StructCompoundAssignStruct)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 myOutput;\n"
            "struct S { float foo; };\n"
            "void main() {\n"
            "   S a, b;\n"
            "   a += b;\n"
            "   myOutput = vec4(0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // struct == different struct is an invalid operation.
    TEST_F(MalformedShaderTest, StructEqDifferentStruct)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 myOutput;\n"
            "struct S { float foo; };\n"
            "struct S2 { float foobar; };\n"
            "void main() {\n"
            "   S a;\n"
            "   S2 b;\n"
            "   a == b;\n"
            "   myOutput = vec4(0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Compute shaders are not supported in versions lower than 310.
    TEST_F(MalformedComputeShaderTest, Version100)
    {
        const std::string &shaderString =
            "void main()\n"
            "layout(local_size_x=1) in;\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Compute shaders are not supported in versions lower than 310.
    TEST_F(MalformedComputeShaderTest, Version300)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "void main()\n"
            "layout(local_size_x=1) in;\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Compute shaders should have work group size specified. However, it is not a compile time error
    // to not have the size specified, but rather a link time one.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, NoWorkGroupSizeSpecified)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Work group size is less than 1. It should be at least 1.
    // GLSL ES 3.10 Revision 4, 7.1.3 Compute Shader Special Variables
    // The spec is not clear whether having a local size qualifier equal zero
    // is correct.
    // TODO (mradev): Ask people from Khronos to clarify the spec.
    TEST_F(MalformedComputeShaderTest, WorkGroupSizeTooSmallXdimension)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 0) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Work group size is correct for the x and y dimensions, but not for the z dimension.
    // GLSL ES 3.10 Revision 4, 7.1.3 Compute Shader Special Variables
    TEST_F(MalformedComputeShaderTest, WorkGroupSizeTooSmallZDimension)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 4, local_size_y = 6, local_size_z = 0) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Work group size is bigger than the minimum in the x dimension.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, WorkGroupSizeTooBigXDimension)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 9989899) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Work group size is bigger than the minimum in the y dimension.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, WorkGroupSizeTooBigYDimension)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5, local_size_y = 9989899) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Work group size is definitely bigger than the minimum in the z dimension.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, WorkGroupSizeTooBigZDimension)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5, local_size_y = 5, local_size_z = 9989899) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Work group size specified through macro expansion.
    TEST_F(MalformedComputeShaderTest, WorkGroupSizeMacro)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "#define MYDEF(x) x"
            "layout(local_size_x = MYDEF(127)) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Work group size specified as an unsigned integer.
    TEST_F(MalformedComputeShaderTest, WorkGroupSizeUnsignedInteger)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 123u) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Work group size specified in hexadecimal.
    TEST_F(MalformedComputeShaderTest, WorkGroupSizeHexadecimal)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 0x3A) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // local_size_x is -1 in hexadecimal format.
    // -1 is used as unspecified value in the TLayoutQualifier structure.
    TEST_F(MalformedComputeShaderTest, WorkGroupSizeMinusOneHexadecimal)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 0xFFFFFFFF) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Work group size specified in octal.
    TEST_F(MalformedComputeShaderTest, WorkGroupSizeOctal)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 013) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Work group size is negative. It is specified in hexadecimal.
    TEST_F(MalformedComputeShaderTest, WorkGroupSizeNegativeHexadecimal)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 0xFFFFFFEC) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Multiple work group layout qualifiers with differing values.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, DifferingLayoutQualifiers)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5, local_size_x = 6) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Multiple work group input variables with differing local size values.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, MultipleInputVariablesDifferingLocalSize)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5, local_size_y = 6) in;\n"
            "layout(local_size_x = 5, local_size_y = 7) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Multiple work group input variables with differing local size values.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, MultipleInputVariablesDifferingLocalSize2)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5) in;\n"
            "layout(local_size_x = 5, local_size_y = 7) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Multiple work group input variables with the same local size values. It should compile.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, MultipleInputVariablesSameLocalSize)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5, local_size_y = 6) in;\n"
            "layout(local_size_x = 5, local_size_y = 6) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Multiple work group input variables with the same local size values. It should compile.
    // Since the default value is 1, it should compile.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, MultipleInputVariablesSameLocalSize2)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5) in;\n"
            "layout(local_size_x = 5, local_size_y = 1) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Multiple work group input variables with the same local size values. It should compile.
    // Since the default value is 1, it should compile.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, MultipleInputVariablesSameLocalSize3)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5, local_size_y = 1) in;\n"
            "layout(local_size_x = 5) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Specifying row_major qualifier in a work group size layout.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, RowMajorInComputeInputLayout)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5, row_major) in;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // local size layout can be used only with compute input variables
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, UniformComputeInputLayout)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5) uniform;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // local size layout can be used only with compute input variables
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, UniformBufferComputeInputLayout)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5) uniform SomeBuffer { vec4 something; };\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // local size layout can be used only with compute input variables
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, StructComputeInputLayout)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5) struct SomeBuffer { vec4 something; };\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // local size layout can be used only with compute input variables
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, StructBodyComputeInputLayout)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "struct S {\n"
            "   layout(local_size_x = 12) vec4 foo;\n"
            "};\n"
            "void main()"
            "{"
            "}";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // local size layout can be used only with compute input variables
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, TypeComputeInputLayout)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5) vec4;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Invalid use of the out storage qualifier in a compute shader.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, InvalidOutStorageQualifier)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 15) in;\n"
            "out vec4 myOutput;\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Invalid use of the out storage qualifier in a compute shader.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, InvalidOutStorageQualifier2)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 15) in;\n"
            "out myOutput;\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Invalid use of the in storage qualifier. Can be only used to describe the local block size.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, InvalidInStorageQualifier)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 15) in;\n"
            "in vec4 myInput;\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Invalid use of the in storage qualifier. Can be only used to describe the local block size.
    // The test checks a different part of the GLSL grammar than what InvalidInStorageQualifier checks.
    // GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
    TEST_F(MalformedComputeShaderTest, InvalidInStorageQualifier2)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 15) in;\n"
            "in myInput;\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // The local_size layout qualifier is only available in compute shaders.
    TEST_F(MalformedVertexShaderGLES31Test, InvalidUseOfLocalSizeX)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "layout(local_size_x = 15) in vec4 myInput;\n"
            "out vec4 myOutput;\n"
            "void main() {\n"
            "   myOutput = myInput;\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // The local_size layout qualifier is only available in compute shaders.
    TEST_F(MalformedFragmentShaderGLES31Test, InvalidUseOfLocalSizeX)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "layout(local_size_x = 15) in vec4 myInput;\n"
            "out vec4 myOutput;\n"
            "void main() {\n"
            "   myOutput = myInput;\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // It is a compile time error to use the gl_WorkGroupSize constant if
    // the local size has not been declared yet.
    // GLSL ES 3.10 Revision 4, 7.1.3 Compute Shader Special Variables
    TEST_F(MalformedComputeShaderTest, InvalidUsageOfWorkGroupSize)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "void main()\n"
            "{\n"
            "   uvec3 WorkGroupSize = gl_WorkGroupSize;\n"
            "}\n"
            "layout(local_size_x = 12) in;\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // The test covers the compute shader built-in variables and constants.
    TEST_F(MalformedComputeShaderTest, CorrectUsageOfComputeBuiltins)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 12) in;\n"
            "void main()\n"
            "{\n"
            "   uvec3 NumWorkGroups = gl_NumWorkGroups;\n"
            "   uvec3 WorkGroupSize = gl_WorkGroupSize;\n"
            "   uvec3 WorkGroupID = gl_WorkGroupID;\n"
            "   uvec3 GlobalInvocationID = gl_GlobalInvocationID;\n"
            "   uvec3 LocalInvocationID = gl_LocalInvocationID;\n"
            "   uint LocalInvocationIndex = gl_LocalInvocationIndex;\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // It is illegal to write to a special variable.
    TEST_F(MalformedComputeShaderTest, SpecialVariableNumWorkGroups)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 12) in;\n"
            "void main()\n"
            "{\n"
            "   gl_NumWorkGroups = uvec3(1); \n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // It is illegal to write to a special variable.
    TEST_F(MalformedComputeShaderTest, SpecialVariableWorkGroupID)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 12) in;\n"
            "void main()\n"
            "{\n"
            "   gl_WorkGroupID = uvec3(1); \n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // It is illegal to write to a special variable.
    TEST_F(MalformedComputeShaderTest, SpecialVariableLocalInvocationID)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 12) in;\n"
            "void main()\n"
            "{\n"
            "   gl_LocalInvocationID = uvec3(1); \n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // It is illegal to write to a special variable.
    TEST_F(MalformedComputeShaderTest, SpecialVariableGlobalInvocationID)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 12) in;\n"
            "void main()\n"
            "{\n"
            "   gl_GlobalInvocationID = uvec3(1); \n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // It is illegal to write to a special variable.
    TEST_F(MalformedComputeShaderTest, SpecialVariableLocalInvocationIndex)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 12) in;\n"
            "void main()\n"
            "{\n"
            "   gl_LocalInvocationIndex = 1; \n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // It is illegal to write to a special variable.
    TEST_F(MalformedComputeShaderTest, SpecialVariableWorkGroupSize)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 12) in;\n"
            "void main()\n"
            "{\n"
            "   gl_WorkGroupSize = uvec3(1); \n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // It is illegal to apply an unary operator to a sampler.
    TEST_F(MalformedShaderTest, SamplerUnaryOperator)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "uniform sampler2D s;\n"
            "void main()\n"
            "{\n"
            "   -s;\n"
            "   gl_FragColor = vec4(0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Invariant cannot be used with a work group size declaration.
    TEST_F(MalformedComputeShaderTest, InvariantBlockSize)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "invariant layout(local_size_x = 15) in;\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Invariant cannot be used with a non-output variable in ESSL3.
    TEST_F(MalformedShaderTest, InvariantNonOuput)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "invariant int value;\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Invariant declaration should follow the following format "invariant <out variable name>".
    // Test having an incorrect qualifier in the invariant declaration.
    TEST_F(MalformedShaderTest, InvariantDeclarationWithStorageQualifier)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 foo;\n"
            "invariant centroid foo;\n"
            "void main() {\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Invariant declaration should follow the following format "invariant <out variable name>".
    // Test having an incorrect precision qualifier in the invariant declaration.
    TEST_F(MalformedShaderTest, InvariantDeclarationWithPrecisionQualifier)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 foo;\n"
            "invariant highp foo;\n"
            "void main() {\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Invariant declaration should follow the following format "invariant <out variable name>".
    // Test having an incorrect layout qualifier in the invariant declaration.
    TEST_F(MalformedShaderTest, InvariantDeclarationWithLayoutQualifier)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 foo;\n"
            "invariant layout(location=0) foo;\n"
            "void main() {\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Variable declaration with both invariant and layout qualifiers is not valid in the formal grammar
    // provided in the ESSL 3.00 spec. ESSL 3.10 starts allowing this combination, but ESSL 3.00 should
    // still disallow it.
    TEST_F(MalformedShaderTest, VariableDeclarationWithInvariantAndLayoutQualifierESSL300)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "invariant layout(location = 0) out vec4 my_FragColor;\n"
            "void main() {\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Bit shift with a rhs value > 31 has an undefined result in the GLSL spec. We disallow it.
    // ESSL 3.00.6 section 5.9.
    TEST_F(MalformedShaderTest, ShiftBy32)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "void main() {\n"
            "   uint u = 1u << 32u;\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Test that deferring global variable init works with an empty main().
    TEST_F(MalformedShaderTest, DeferGlobalVariableInitWithEmptyMain)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "uniform float u;\n"
            "float foo = u;\n"
            "void main() {}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Test that pruning empty declarations from loop init expression works.
    TEST_F(MalformedShaderTest, EmptyDeclarationAsLoopInit)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "    int i = 0;\n"
            "    for (int; i < 3; i++)\n"
            "    {\n"
            "        my_FragColor = vec4(i);\n"
            "    }\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    // r32f, r32i, r32ui do not require either the writeonly or readonly memory qualifiers.
    // GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers
    TEST_F(MalformedFragmentShaderGLES31Test, ImageR32FNoMemoryQualifier)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "in vec4 myInput;\n"
            "layout(r32f) uniform image2D myImage;\n"
            "void main() {\n"
            "}\n";
    
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Images which do not have r32f, r32i or r32ui as internal format, must have readonly or writeonly
    // specified.
    // GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers
    TEST_F(MalformedFragmentShaderGLES31Test, ImageR32FWithCorrectMemoryQualifier)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "in vec4 myInput;\n"
            "layout(rgba32f) uniform image2D myImage;\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // It is a compile-time error to call imageStore when the image is qualified as readonly.
    // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
    TEST_F(MalformedFragmentShaderGLES31Test, StoreInReadOnlyImage)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "in vec4 myInput;\n"
            "layout(r32f) uniform readonly image2D myImage;\n"
            "void main() {\n"
            "   imageStore(myImage, ivec2(0), vec4(1.0));\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // It is a compile-time error to call imageLoad when the image is qualified as writeonly.
    // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
    TEST_F(MalformedFragmentShaderGLES31Test, LoadFromWriteOnlyImage)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "in vec4 myInput;\n"
            "layout(r32f) uniform writeonly image2D myImage;\n"
            "void main() {\n"
            "   imageLoad(myImage, ivec2(0));\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // A valid declaration and usage of an image3D.
    TEST_F(MalformedFragmentShaderGLES31Test, ValidImage3D)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image3D;\n"
            "in vec4 myInput;\n"
            "layout(rgba32f) uniform readonly image3D myImage;\n"
            "void main() {\n"
            "   imageLoad(myImage, ivec3(0));\n"
            "}\n";
    
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // A valid declaration and usage of an imageCube.
    TEST_F(MalformedFragmentShaderGLES31Test, ValidImageCube)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump imageCube;\n"
            "in vec4 myInput;\n"
            "layout(rgba32f) uniform readonly imageCube myImage;\n"
            "void main() {\n"
            "   imageLoad(myImage, ivec3(0));\n"
            "}\n";
    
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // A valid declaration and usage of an image2DArray.
    TEST_F(MalformedFragmentShaderGLES31Test, ValidImage2DArray)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2DArray;\n"
            "in vec4 myInput;\n"
            "layout(rgba32f) uniform readonly image2DArray myImage;\n"
            "void main() {\n"
            "   imageLoad(myImage, ivec3(0));\n"
            "}\n";
    
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Images cannot be l-values.
    // GLSL ES 3.10 Revision 4, 4.1.7 Opaque Types
    TEST_F(MalformedFragmentShaderGLES31Test, ImageLValueFunctionDefinitionInOut)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "void myFunc(inout image2D someImage) {}\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Cannot assign to images.
    // GLSL ES 3.10 Revision 4, 4.1.7 Opaque Types
    TEST_F(MalformedFragmentShaderGLES31Test, ImageAssignment)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "layout(rgba32f) uniform readonly image2D myImage;\n"
            "layout(rgba32f) uniform readonly image2D myImage2;\n"
            "void main() {\n"
            "   myImage = myImage2;\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Passing an image qualifier to a function should not be able to discard the readonly qualifier.
    // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
    TEST_F(MalformedFragmentShaderGLES31Test, ReadOnlyQualifierMissingInFunctionArgument)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "layout(rgba32f) uniform readonly image2D myImage;\n"
            "void myFunc(in image2D someImage) {}\n"
            "void main() {\n"
            "   myFunc(myImage);\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Passing an image qualifier to a function should not be able to discard the writeonly qualifier.
    // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
    TEST_F(MalformedFragmentShaderGLES31Test, WriteOnlyQualifierMissingInFunctionArgument)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "layout(rgba32f) uniform writeonly image2D myImage;\n"
            "void myFunc(in image2D someImage) {}\n"
            "void main() {\n"
            "   myFunc(myImage);\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Passing an image parameter as an argument to another function should not be able to discard the
    // writeonly qualifier.
    // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
    TEST_F(MalformedFragmentShaderGLES31Test, DiscardWriteonlyInFunctionBody)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "layout(rgba32f) uniform writeonly image2D myImage;\n"
            "void myFunc1(in image2D someImage) {}\n"
            "void myFunc2(in writeonly image2D someImage) { myFunc1(someImage); }\n"
            "void main() {\n"
            "   myFunc2(myImage);\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // The memory qualifiers for the image declaration and function argument match and the test should
    // pass.
    TEST_F(MalformedFragmentShaderGLES31Test, CorrectImageMemoryQualifierSpecified)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "layout(r32f) uniform image2D myImage;\n"
            "void myFunc(in image2D someImage) {}\n"
            "void main() {\n"
            "   myFunc(myImage);\n"
            "}\n";
    
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // The test adds additional qualifiers to the argument in the function header.
    // This is correct since no memory qualifiers are discarded upon the function call.
    // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
    TEST_F(MalformedFragmentShaderGLES31Test, CorrectImageMemoryQualifierSpecified2)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "layout(r32f) uniform image2D myImage;\n"
            "void myFunc(in readonly writeonly image2D someImage) {}\n"
            "void main() {\n"
            "   myFunc(myImage);\n"
            "}\n";
    
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Images are not allowed in structs.
    // GLSL ES 3.10 Revision 4, 4.1.8 Structures
    TEST_F(MalformedFragmentShaderGLES31Test, ImageInStruct)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "struct myStruct { layout(r32f) image2D myImage; };\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Images are not allowed in interface blocks.
    // GLSL ES 3.10 Revision 4, 4.3.9 Interface Blocks
    TEST_F(MalformedFragmentShaderGLES31Test, ImageInInterfaceBlock)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "uniform myBlock { layout(r32f) image2D myImage; };\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Readonly used with an interface block.
    TEST_F(MalformedFragmentShaderGLES31Test, ReadonlyWithInterfaceBlock)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "uniform readonly myBlock { float something; };\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Readonly used with an invariant.
    TEST_F(MalformedFragmentShaderGLES31Test, ReadonlyWithInvariant)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "out vec4 something;\n"
            "invariant readonly something;\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Readonly used with a member of a structure.
    TEST_F(MalformedFragmentShaderGLES31Test, ReadonlyWithStructMember)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "out vec4 something;\n"
            "struct MyStruct { readonly float myMember; };\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // It should not be possible to use an internal format layout qualifier with an interface block.
    TEST_F(MalformedFragmentShaderGLES31Test, ImageInternalFormatWithInterfaceBlock)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "out vec4 something;\n"
            "layout(rgba32f) uniform MyStruct { float myMember; };\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // It should not be possible to use an internal format layout qualifier with a uniform without a
    // type.
    TEST_F(MalformedFragmentShaderGLES31Test, ImageInternalFormatInGlobalLayoutQualifier)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "out vec4 something;\n"
            "layout(rgba32f) uniform;\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // ESSL 1.00 section 4.1.7.
    // Samplers are not allowed as operands for most operations. Test this for ternary operator.
    TEST_F(MalformedShaderTest, SamplerAsTernaryOperand)
    {
        const std::string &shaderString =
            "precision mediump float;\n"
            "uniform bool u;\n"
            "uniform sampler2D s1;\n"
            "uniform sampler2D s2;\n"
            "void main() {\n"
            "    gl_FragColor = texture2D(u ? s1 : s2, vec2(0, 0));\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // ESSL 1.00.17 section 4.5.2.
    // ESSL 3.00.6 section 4.5.3.
    // Precision must be specified for floats. Test this with a declaration with no qualifiers.
    TEST_F(MalformedShaderTest, FloatDeclarationNoQualifiersNoPrecision)
    {
        const std::string &shaderString =
            "vec4 foo = vec4(0.0);\n"
            "void main()\n"
            "{\n"
            "    gl_FragColor = foo;\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Check compiler doesn't crash on incorrect unsized array declarations.
    TEST_F(MalformedShaderTest, IncorrectUnsizedArray)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "float foo[] = 0.0;\n"
            "out vec4 my_FragColor;\n"
            "void main()\n"
            "{\n"
            "    foo[0] = 1.0;\n"
            "    my_FragColor = vec4(foo[0]);\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Check compiler doesn't crash when a bvec is on the right hand side of a logical operator.
    // ESSL 3.00.6 section 5.9.
    TEST_F(MalformedShaderTest, LogicalOpRHSIsBVec)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "void main()\n"
            "{\n"
            "    bool b;\n"
            "    bvec3 b3;\n"
            "    b && b3;\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Check compiler doesn't crash when there's an unsized array constructor with no parameters.
    // ESSL 3.00.6 section 4.1.9: Array size must be greater than zero.
    TEST_F(MalformedShaderTest, UnsizedArrayConstructorNoParameters)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "void main()\n"
            "{\n"
            "    int[]();\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Passing an image parameter as an argument to another function should not be able to discard the
    // coherent qualifier.
    TEST_F(MalformedFragmentShaderGLES31Test, CoherentQualifierMissingInFunctionArgument)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "layout(r32f) uniform coherent image2D myImage;\n"
            "void myFunc(in image2D someImage) {}\n"
            "void main() {\n"
            "   myFunc(myImage);\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Passing an image parameter as an argument to another function should not be able to discard the
    // volatile qualifier.
    TEST_F(MalformedFragmentShaderGLES31Test, VolatileQualifierMissingInFunctionArgument)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "layout(r32f) uniform volatile image2D myImage;\n"
            "void myFunc(in image2D someImage) {}\n"
            "void main() {\n"
            "   myFunc(myImage);\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // The restrict qualifier can be discarded from a function argument.
    // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
    TEST_F(MalformedFragmentShaderGLES31Test, RestrictQualifierDiscardedInFunctionArgument)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "layout(r32f) uniform restrict image2D myImage;\n"
            "void myFunc(in image2D someImage) {}\n"
            "void main() {\n"
            "   myFunc(myImage);\n"
            "}\n";
    
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Function image arguments can be overqualified.
    // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
    TEST_F(MalformedFragmentShaderGLES31Test, OverqualifyingImageParameter)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "precision mediump image2D;\n"
            "layout(r32f) uniform image2D myImage;\n"
            "void myFunc(in coherent volatile image2D someImage) {}\n"
            "void main() {\n"
            "   myFunc(myImage);\n"
            "}\n";
    
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Test that work group size can be used to size arrays.
    // GLSL ES 3.10.4 section 7.1.3 Compute Shader Special Variables
    TEST_F(MalformedComputeShaderTest, WorkGroupSizeAsArraySize)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "layout(local_size_x = 5, local_size_y = 3, local_size_z = 1) in;\n"
            "void main()\n"
            "{\n"
            "    int[gl_WorkGroupSize.x] a = int[5](0, 0, 0, 0, 0);\n"
            "    int[gl_WorkGroupSize.y] b = int[3](0, 0, 0);\n"
            "    int[gl_WorkGroupSize.z] c = int[1](0);\n"
            "}\n";
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Shared memory variables cannot be used inside a vertex shader.
    // GLSL ES 3.10 Revision 4, 4.3.8 Shared Variables
    TEST_F(MalformedVertexShaderGLES31Test, VertexShaderSharedMemory)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "in vec4 i;\n"
            "shared float myShared[10];\n"
            "void main() {\n"
            "    gl_Position = i;\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Shared memory variables cannot be used inside a fragment shader.
    // GLSL ES 3.10 Revision 4, 4.3.8 Shared Variables
    TEST_F(MalformedFragmentShaderGLES31Test, FragmentShaderSharedMemory)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "shared float myShared[10];\n"
            "out vec4 color;\n"
            "void main() {\n"
            "   color = vec4(1.0);\n"
            "}\n";
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Shared memory cannot be combined with any other storage qualifier.
    TEST_F(MalformedComputeShaderTest, UniformSharedMemory)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "layout(local_size_x = 5) in;\n"
            "uniform shared float myShared[100];\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Correct usage of shared memory variables.
    TEST_F(MalformedComputeShaderTest, CorrectUsageOfSharedMemory)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "layout(local_size_x = 5) in;\n"
            "shared float myShared[100];\n"
            "void main() {\n"
            "   myShared[gl_LocalInvocationID.x] = 1.0;\n"
            "}\n";
    
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }
    
    // Shared memory variables cannot be initialized.
    // GLSL ES 3.10 Revision 4, 4.3.8 Shared Variables
    TEST_F(MalformedComputeShaderTest, SharedVariableInitialization)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "layout(local_size_x = 5) in;\n"
            "shared int myShared = 0;\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Local variables cannot be qualified as shared.
    // GLSL ES 3.10 Revision 4, 4.3 Storage Qualifiers
    TEST_F(MalformedComputeShaderTest, SharedMemoryInFunctionBody)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "layout(local_size_x = 5) in;\n"
            "void func() {\n"
            "   shared int myShared;\n"
            "}\n"
            "void main() {\n"
            "   func();\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Struct members cannot be qualified as shared.
    TEST_F(MalformedComputeShaderTest, SharedMemoryInStruct)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "layout(local_size_x = 5) in;\n"
            "struct MyStruct {\n"
            "   shared int myShared;\n"
            "};\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Interface block members cannot be qualified as shared.
    TEST_F(MalformedComputeShaderTest, SharedMemoryInInterfaceBlock)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "layout(local_size_x = 5) in;\n"
            "uniform Myblock {\n"
            "   shared int myShared;\n"
            "};\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // The shared qualifier cannot be used with any other qualifier.
    TEST_F(MalformedComputeShaderTest, SharedWithInvariant)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "layout(local_size_x = 5) in;\n"
            "invariant shared int myShared;\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // The shared qualifier cannot be used with any other qualifier.
    TEST_F(MalformedComputeShaderTest, SharedWithMemoryQualifier)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "layout(local_size_x = 5) in;\n"
            "readonly shared int myShared;\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // The shared qualifier cannot be used with any other qualifier.
    TEST_F(MalformedComputeShaderTest, SharedGlobalLayoutDeclaration)
    {
        const std::string &shaderString =
            "#version 310 es\n"
            "precision mediump float;\n"
            "layout(local_size_x = 5) in;\n"
            "layout(row_major) shared mat4;\n"
            "void main() {\n"
            "}\n";
    
        if (compile(shaderString))
        {
            FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
        }
    }
    
    // Declaring a function with the same name as a built-in from a higher ESSL version should not cause
    // a redeclaration error.
    TEST_F(MalformedShaderTest, BuiltinESSL31FunctionDeclaredInESSL30Shader)
    {
        const std::string &shaderString =
            "#version 300 es\n"
            "precision mediump float;\n"
            "void imageSize() {}\n"
            "void main() {\n"
            "   imageSize();\n"
            "}\n";
    
        if (!compile(shaderString))
        {
            FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
        }
    }