Commit b5f88853 by Arun Patole Committed by Jamie Madill

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 overloading or redefining builtin functions is an error. This is fixed by inserting unmangled built-ins into the symbol table and then checking if the new function declaration matches any of the built-in in symbol table. BUG=angleproject:1066 TEST=angle_unittests(new: ParseESSLFunctionsTest), dEQP Tests dEQP-GLES3.functional.shaders.functions.invalid.overload_builtin_function* (2 tests started passing with this change) Change-Id: I0e027e588664e604f29c130028178315c3e21631 Reviewed-on: https://chromium-review.googlesource.com/287801Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 6db9adac
......@@ -2009,18 +2009,26 @@ void TParseContext::parseFunctionPrototype(const TSourceLoc &location,
TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TFunction *function)
{
//
// Multiple declarations of the same function are allowed.
//
// If this is a definition, the definition production code will check for redefinitions
// (we don't know at this point if it's a definition or not).
//
// Redeclarations are allowed. But, return types and parameter qualifiers must match.
//
TFunction *prevDec =
static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
if (prevDec)
TFunction *prevDec = static_cast<TFunction*>(symbolTable.find(function->getMangledName(), getShaderVersion()));
bool builtIn;
TSymbol *prevSym = symbolTable.find(function->getName(), getShaderVersion(), &builtIn);
if (getShaderVersion() >= 300 && prevSym && builtIn)
{
// 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)
{
//
// Multiple declarations of the same function are allowed.
//
// If this is a definition, the definition production code will check for redefinitions
// (we don't know at this point if it's a definition or not).
//
// Redeclarations are allowed. But, return types and parameter qualifiers must match.
//
if (prevDec->getReturnType() != function->getReturnType())
{
error(location, "overloaded functions must have the same return type",
......@@ -2042,7 +2050,6 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF
//
// Check for previously declared variables using the same name.
//
TSymbol *prevSym = symbolTable.find(function->getName(), getShaderVersion());
if (prevSym)
{
if (!prevSym->isFunction())
......
......@@ -199,6 +199,7 @@ void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *e
{
if (ptype1->getBasicType() == EbtGSampler2D)
{
insertUnmangled(level, 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 @@ void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *e
}
else if (ptype1->getBasicType() == EbtGSampler3D)
{
insertUnmangled(level, 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 @@ void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *e
}
else if (ptype1->getBasicType() == EbtGSamplerCube)
{
insertUnmangled(level, 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 @@ void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *e
}
else if (ptype1->getBasicType() == EbtGSampler2DArray)
{
insertUnmangled(level, 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 @@ void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *e
else if (IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3))
{
ASSERT(!ptype4 && !ptype5);
insertUnmangled(level, 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 @@ void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *e
else if (IsVecType(rvalue) || IsVecType(ptype1) || IsVecType(ptype2) || IsVecType(ptype3))
{
ASSERT(!ptype4 && !ptype5);
insertUnmangled(level, 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 @@ void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *e
function->addParameter(TConstParameter(ptype5));
}
ASSERT(table[level]->find(name));
insert(level, function);
}
}
......
......@@ -418,18 +418,21 @@ class TSymbolTable : angle::NonCopyable
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)
{
insertUnmangled(level, 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)
{
insertUnmangled(level, 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)
{
insertUnmangled(level, name);
insertBuiltIn(level, op, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
}
......@@ -491,6 +494,12 @@ class TSymbolTable : angle::NonCopyable
return static_cast<ESymbolLevel>(table.size() - 1);
}
// Used to insert unmangled functions to check redeclaration of built-ins later for ESSL 3.00.
bool insertUnmangled(ESymbolLevel level, const char *name)
{
return table[level]->insertUnmangled(new TFunction(NewPoolTString(name), new TType()));
}
std::vector<TSymbolTableLevel *> table;
typedef TMap<TBasicType, TPrecision> PrecisionStackLevel;
std::vector< PrecisionStackLevel *> precisionStack;
......
......@@ -42,6 +42,7 @@
'<(angle_path)/src/tests/compiler_tests/MalformedShader_test.cpp',
'<(angle_path)/src/tests/compiler_tests/NV_draw_buffers_test.cpp',
'<(angle_path)/src/tests/compiler_tests/Pack_Unpack_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ParseESSLFunctions_test.cpp',
'<(angle_path)/src/tests/compiler_tests/PruneUnusedFunctions_test.cpp',
'<(angle_path)/src/tests/compiler_tests/RecordConstantPrecision_test.cpp',
'<(angle_path)/src/tests/compiler_tests/RemovePow_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.
//
// ParseESSLFunctions_test.cpp:
// Tests for ESSL built-in functons.
//
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "GLSLANG/ShaderLang.h"
#include "compiler/translator/PoolAlloc.h"
#include "compiler/translator/TranslatorESSL.h"
namespace
{
class ParseESSLFunctionsTest : public testing::Test
{
public:
ParseESSLFunctionsTest() {}
protected:
void SetUp()
{
mAllocator.push();
SetGlobalPoolAllocator(&mAllocator);
ShBuiltInResources resources;
ShInitBuiltInResources(&resources);
mTranslatorESSL = new TranslatorESSL(GL_VERTEX_SHADER, SH_GLES3_SPEC);
ASSERT_TRUE(mTranslatorESSL->Init(resources));
}
void TearDown()
{
delete mTranslatorESSL;
SetGlobalPoolAllocator(NULL);
mAllocator.pop();
}
bool compile(const std::string& shaderString)
{
const char *shaderStrings[] = { shaderString.c_str() };
return mTranslatorESSL->compileTreeForTesting(shaderStrings, 1, SH_OBJECT_CODE) != nullptr;
}
private:
TranslatorESSL *mTranslatorESSL;
TPoolAllocator mAllocator;
};
// Tests that cimpilation succeeds for built-in function overload in ESSL 1.00.
TEST_F(ParseESSLFunctionsTest, ESSL100BuiltInFunctionOverload)
{
const std::string &shaderString =
"precision mediump float;\n"
"int sin(int x) {\n"
" return int(sin(float(x)));\n"
"}\n"
"void main() {\n"
" gl_Position = vec4(sin(1));"
"}\n";
EXPECT_TRUE(compile(shaderString));
}
// Tests that cimpilation fails for built-in function redefinition in ESSL 1.00.
TEST_F(ParseESSLFunctionsTest, ESSL100BuiltInFunctionRedefinition)
{
const std::string &shaderString =
"precision mediump float;\n"
"float sin(float x) {\n"
" return sin(0.0);\n"
"}\n"
"void main() {\n"
" gl_Position = vec4(sin(1.0));\n"
"}\n";
EXPECT_FALSE(compile(shaderString));
}
} // namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment