Names of built-in functions cannot be redeclared as functions

With ESSL 3.00, names of built-in functions cannot be redeclared as
functions, and therefore an error needs to be generated if a built-in
function is overloaded.

This is fixed by inserting unmangled built-ins into a special set in
the symbol table and checking if function declarations match any of
the built-ins in the set.

The regular symbol table structures can't be used for storing the
unmangled names because that interferes with name hashing in
OutputGLSL.

Credit goes to Arun Patole, apatole@nvidia.com for initially
investigating this issue and developing the first version of the
patch.

BUG=angleproject:1066
TEST=angle_unittests,
dEQP-GLES3.functional.shaders.functions.invalid.overload_builtin_function*
(2 tests started passing with this change)

Change-Id: I28c8325f5a3a8f4a97226b0dfdbb9762724fa609
Reviewed-on: https://chromium-review.googlesource.com/328994
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 235351c..7f67daa 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -2117,7 +2117,16 @@
     //
     TFunction *prevDec =
         static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
-    if (prevDec)
+
+    if (getShaderVersion() >= 300 && symbolTable.hasUnmangledBuiltIn(function->getName().c_str()))
+    {
+        // With ESSL 3.00, names of built-in functions cannot be redeclared as functions.
+        // Therefore overloading or redefining builtin functions is an error.
+        error(location, "Name of a built-in function cannot be redeclared as function",
+              function->getName().c_str());
+        recover();
+    }
+    else if (prevDec)
     {
         if (prevDec->getReturnType() != function->getReturnType())
         {
diff --git a/src/compiler/translator/SymbolTable.cpp b/src/compiler/translator/SymbolTable.cpp
index dc8f8e3..f578909 100644
--- a/src/compiler/translator/SymbolTable.cpp
+++ b/src/compiler/translator/SymbolTable.cpp
@@ -199,6 +199,7 @@
 {
     if (ptype1->getBasicType() == EbtGSampler2D)
     {
+        insertUnmangledBuiltIn(name);
         bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
         insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name, TCache::getType(EbtSampler2D), ptype2, ptype3, ptype4, ptype5);
         insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISampler2D), ptype2, ptype3, ptype4, ptype5);
@@ -206,6 +207,7 @@
     }
     else if (ptype1->getBasicType() == EbtGSampler3D)
     {
+        insertUnmangledBuiltIn(name);
         bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
         insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name, TCache::getType(EbtSampler3D), ptype2, ptype3, ptype4, ptype5);
         insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISampler3D), ptype2, ptype3, ptype4, ptype5);
@@ -213,6 +215,7 @@
     }
     else if (ptype1->getBasicType() == EbtGSamplerCube)
     {
+        insertUnmangledBuiltIn(name);
         bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
         insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name, TCache::getType(EbtSamplerCube), ptype2, ptype3, ptype4, ptype5);
         insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISamplerCube), ptype2, ptype3, ptype4, ptype5);
@@ -220,6 +223,7 @@
     }
     else if (ptype1->getBasicType() == EbtGSampler2DArray)
     {
+        insertUnmangledBuiltIn(name);
         bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
         insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name, TCache::getType(EbtSampler2DArray), ptype2, ptype3, ptype4, ptype5);
         insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5);
@@ -228,6 +232,7 @@
     else if (IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3))
     {
         ASSERT(!ptype4 && !ptype5);
+        insertUnmangledBuiltIn(name);
         insertBuiltIn(level, op, ext, SpecificType(rvalue, 1), name, SpecificType(ptype1, 1), SpecificType(ptype2, 1), SpecificType(ptype3, 1));
         insertBuiltIn(level, op, ext, SpecificType(rvalue, 2), name, SpecificType(ptype1, 2), SpecificType(ptype2, 2), SpecificType(ptype3, 2));
         insertBuiltIn(level, op, ext, SpecificType(rvalue, 3), name, SpecificType(ptype1, 3), SpecificType(ptype2, 3), SpecificType(ptype3, 3));
@@ -236,6 +241,7 @@
     else if (IsVecType(rvalue) || IsVecType(ptype1) || IsVecType(ptype2) || IsVecType(ptype3))
     {
         ASSERT(!ptype4 && !ptype5);
+        insertUnmangledBuiltIn(name);
         insertBuiltIn(level, op, ext, VectorType(rvalue, 2), name, VectorType(ptype1, 2), VectorType(ptype2, 2), VectorType(ptype3, 2));
         insertBuiltIn(level, op, ext, VectorType(rvalue, 3), name, VectorType(ptype1, 3), VectorType(ptype2, 3), VectorType(ptype3, 3));
         insertBuiltIn(level, op, ext, VectorType(rvalue, 4), name, VectorType(ptype1, 4), VectorType(ptype2, 4), VectorType(ptype3, 4));
@@ -266,6 +272,7 @@
             function->addParameter(TConstParameter(ptype5));
         }
 
+        ASSERT(hasUnmangledBuiltIn(name));
         insert(level, function);
     }
 }
diff --git a/src/compiler/translator/SymbolTable.h b/src/compiler/translator/SymbolTable.h
index 2706149..6de7c98 100644
--- a/src/compiler/translator/SymbolTable.h
+++ b/src/compiler/translator/SymbolTable.h
@@ -405,18 +405,21 @@
     void insertBuiltIn(ESymbolLevel level, const TType *rvalue, const char *name,
                        const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0)
     {
+        insertUnmangledBuiltIn(name);
         insertBuiltIn(level, EOpNull, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
     }
 
     void insertBuiltIn(ESymbolLevel level, const char *ext, const TType *rvalue, const char *name,
                        const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0)
     {
+        insertUnmangledBuiltIn(name);
         insertBuiltIn(level, EOpNull, ext, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
     }
 
     void insertBuiltIn(ESymbolLevel level, TOperator op, const TType *rvalue, const char *name,
                        const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0)
     {
+        insertUnmangledBuiltIn(name);
         insertBuiltIn(level, op, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
     }
 
@@ -474,16 +477,29 @@
         return ++uniqueIdCounter;
     }
 
+    bool hasUnmangledBuiltIn(const char *name)
+    {
+        return mUnmangledBuiltinNames.count(std::string(name)) > 0;
+    }
+
   private:
     ESymbolLevel currentLevel() const
     {
         return static_cast<ESymbolLevel>(table.size() - 1);
     }
 
+    // Used to insert unmangled functions to check redeclaration of built-ins in ESSL 3.00.
+    void insertUnmangledBuiltIn(const char *name)
+    {
+        mUnmangledBuiltinNames.insert(std::string(name));
+    }
+
     std::vector<TSymbolTableLevel *> table;
     typedef TMap<TBasicType, TPrecision> PrecisionStackLevel;
     std::vector< PrecisionStackLevel *> precisionStack;
 
+    std::set<std::string> mUnmangledBuiltinNames;
+
     std::set<std::string> mInvariantVaryings;
     bool mGlobalInvariant;
 
diff --git a/src/tests/compiler_tests/MalformedShader_test.cpp b/src/tests/compiler_tests/MalformedShader_test.cpp
index b072834..5e602f4 100644
--- a/src/tests/compiler_tests/MalformedShader_test.cpp
+++ b/src/tests/compiler_tests/MalformedShader_test.cpp
@@ -1532,3 +1532,43 @@
         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;
+    }
+}