From b88c60b03fe1259d9b7963e268a68ebc5ab9c9f9 Mon Sep 17 00:00:00 2001
From: John Kessenich <cepheus@frii.com>
Date: Wed, 4 Dec 2013 19:43:05 +0000
Subject: [PATCH] Track whether function declarations are prototypes, and only
 allow at most one prototype for ES 100.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@24342 e7fa87d3-cd2b-0410-9028-fcbf551c1848
---
 Test/100.frag                              | 12 +++++++-
 Test/300.vert                              | 10 +++++++
 Test/baseResults/100.frag.out              | 28 +++++++++++++++++--
 Test/baseResults/100scope.vert.out         |  2 +-
 Test/baseResults/300.vert.out              | 14 ++++++++++
 Test/baseResults/300scope.vert.out         |  8 +++---
 Test/baseResults/430scope.vert.out         |  2 +-
 glslang/Include/revision.h                 |  4 +--
 glslang/MachineIndependent/ParseHelper.cpp | 32 +++++++++++++++-------
 glslang/MachineIndependent/ParseHelper.h   |  2 +-
 glslang/MachineIndependent/SymbolTable.cpp |  1 +
 glslang/MachineIndependent/SymbolTable.h   |  7 +++--
 glslang/MachineIndependent/glslang.y       |  4 ++-
 13 files changed, 101 insertions(+), 25 deletions(-)

diff --git a/Test/100.frag b/Test/100.frag
index 51e2c5f00..d6e62a0c8 100644
--- a/Test/100.frag
+++ b/Test/100.frag
@@ -164,6 +164,16 @@ void foo323433()
 }
 
 int fgfg(float f, mediump int i);
-int fgfg(float f, highp int i);   // ERROR, precision qualifier difference
+int fgfg(float f, highp int i) { return 2; }   // ERROR, precision qualifier difference
+
+int fffg(float f);
+int fffg(float f);  // ERROR, can't have multiple prototypes 
+
+int gggf(float f);
+int gggf(float f) { return 2; }
+
+int agggf(float f) { return 2; }
+int agggf(float f);
+int agggf(float f);  // ERROR, second prototype
 
 uniform samplerExternalOES badExt;  // syntax ERROR
diff --git a/Test/300.vert b/Test/300.vert
index a5d06c3e5..29453cfa2 100644
--- a/Test/300.vert
+++ b/Test/300.vert
@@ -147,3 +147,13 @@ int[] foo213234();        // ERROR
 int foo234234(float[]);   // ERROR
 int foo234235(vec2[] v);  // ERROR
 precision highp float[2]; // ERROR
+
+int fffg(float f);
+int fffg(float f);
+
+int gggf(float f);
+int gggf(float f) { return 2; }
+int gggf(float f);
+
+int agggf(float f) { return 2; }
+int agggf(float f);
diff --git a/Test/baseResults/100.frag.out b/Test/baseResults/100.frag.out
index 4a53c1c7e..83a7ce14a 100644
--- a/Test/baseResults/100.frag.out
+++ b/Test/baseResults/100.frag.out
@@ -63,8 +63,10 @@ ERROR: 0:147: 'texture2DProjGradEXT' : required extension not requested: GL_EXT_
 ERROR: 0:151: 'floating-point suffix' : not supported for this version or the enabled extensions 
 ERROR: 0:152: 'floating-point suffix' : not supported for this version or the enabled extensions 
 ERROR: 0:167: 'highp' : overloaded functions must have the same parameter precision qualifiers for argument 2
-ERROR: 0:169: '' :  syntax error
-ERROR: 58 compilation errors.  No code generated.
+ERROR: 0:170: 'multiple prototypes for same function' : not supported for this version or the enabled extensions 
+ERROR: 0:177: 'multiple prototypes for same function' : not supported for this version or the enabled extensions 
+ERROR: 0:179: '' :  syntax error
+ERROR: 60 compilation errors.  No code generated.
 
 
 ERROR: node is still EOpNull!
@@ -294,6 +296,28 @@ ERROR: node is still EOpNull!
 0:163          'f13' (invariant mediump float)
 0:163        Construct vec3 (3-component vector of float)
 0:163          'f13' (invariant mediump float)
+0:167  Function Definition: fgfg(f1;i1; (mediump int)
+0:167    Function Parameters: 
+0:167      'f' (in mediump float)
+0:167      'i' (in highp int)
+0:167    Sequence
+0:167      Branch: Return with expression
+0:167        Constant:
+0:167          2 (const int)
+0:173  Function Definition: gggf(f1; (mediump int)
+0:173    Function Parameters: 
+0:173      'f' (in mediump float)
+0:173    Sequence
+0:173      Branch: Return with expression
+0:173        Constant:
+0:173          2 (const int)
+0:175  Function Definition: agggf(f1; (mediump int)
+0:175    Function Parameters: 
+0:175      'f' (in mediump float)
+0:175    Sequence
+0:175      Branch: Return with expression
+0:175        Constant:
+0:175          2 (const int)
 0:?   Linker Objects
 0:?     'a' (3-element array of mediump int)
 0:?     'uint' (mediump int)
diff --git a/Test/baseResults/100scope.vert.out b/Test/baseResults/100scope.vert.out
index 02f1ad413..0063ec5fa 100644
--- a/Test/baseResults/100scope.vert.out
+++ b/Test/baseResults/100scope.vert.out
@@ -1,6 +1,6 @@
 100scope.vert
 ERROR: 0:5: 'a' : redefinition 
-ERROR: 0:17: 'b' : redeclaration of existing name 
+ERROR: 0:17: 'b' : function name is redeclaration of existing name 
 ERROR: 0:19: 'f' : redefinition 
 ERROR: 0:21: 'redefinition of built-in function' : not supported with this profile: es
 ERROR: 0:22: 'redefinition of built-in function' : not supported with this profile: es
diff --git a/Test/baseResults/300.vert.out b/Test/baseResults/300.vert.out
index c70fc558a..156914dbf 100644
--- a/Test/baseResults/300.vert.out
+++ b/Test/baseResults/300.vert.out
@@ -241,6 +241,20 @@ ERROR: node is still EOpNull!
 0:143      move second child to first child (3-element array of highp float)
 0:143        'w' (3-element array of highp float)
 0:143        'y' (3-element array of highp float)
+0:155  Function Definition: gggf(f1; (highp int)
+0:155    Function Parameters: 
+0:155      'f' (in highp float)
+0:155    Sequence
+0:155      Branch: Return with expression
+0:155        Constant:
+0:155          2 (const int)
+0:158  Function Definition: agggf(f1; (highp int)
+0:158    Function Parameters: 
+0:158      'f' (in highp float)
+0:158    Sequence
+0:158      Branch: Return with expression
+0:158        Constant:
+0:158          2 (const int)
 0:?   Linker Objects
 0:?     'm43' (uniform highp 4X3 matrix of float)
 0:?     'm33' (uniform highp 3X3 matrix of float)
diff --git a/Test/baseResults/300scope.vert.out b/Test/baseResults/300scope.vert.out
index aa7f37e42..a51f24aac 100644
--- a/Test/baseResults/300scope.vert.out
+++ b/Test/baseResults/300scope.vert.out
@@ -1,15 +1,15 @@
 300scope.vert
 ERROR: 0:5: 'a' : redefinition 
-ERROR: 0:17: 'b' : redeclaration of existing name 
+ERROR: 0:17: 'b' : function name is redeclaration of existing name 
 ERROR: 0:19: 'f' : redefinition 
 ERROR: 0:20: 'tan' : redefinition 
 ERROR: 0:21: 'redefinition of built-in function' : not supported with this profile: es
-ERROR: 0:21: 'sin' : redeclaration of existing name 
+ERROR: 0:21: 'sin' : function name is redeclaration of existing name 
 ERROR: 0:22: 'redefinition of built-in function' : not supported with this profile: es
-ERROR: 0:22: 'cos' : redeclaration of existing name 
+ERROR: 0:22: 'cos' : function name is redeclaration of existing name 
 ERROR: 0:22: 'cos' : function already has a body 
 ERROR: 0:24: 'return' : void function cannot return a value 
-ERROR: 0:26: 'radians' : redeclaration of existing name 
+ERROR: 0:26: 'radians' : function name is redeclaration of existing name 
 ERROR: 0:26: 'radians' : can't find function 
 ERROR: 0:28: 'return' : void function cannot return a value 
 ERROR: 0:35: 'local function declaration' : not supported with this profile: es
diff --git a/Test/baseResults/430scope.vert.out b/Test/baseResults/430scope.vert.out
index c87f3ee54..1dcd5f66a 100644
--- a/Test/baseResults/430scope.vert.out
+++ b/Test/baseResults/430scope.vert.out
@@ -1,7 +1,7 @@
 430scope.vert
 Warning, version 430 is not yet complete; some version-specific features are present, but many are missing.
 ERROR: 0:5: 'a' : redefinition 
-ERROR: 0:17: 'b' : redeclaration of existing name 
+ERROR: 0:17: 'b' : function name is redeclaration of existing name 
 ERROR: 0:19: 'f' : redefinition 
 ERROR: 0:54: 'z' : undeclared identifier 
 ERROR: 0:54: 'z' : redefinition 
diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h
index 3712b7b6b..b2ae39920 100644
--- a/glslang/Include/revision.h
+++ b/glslang/Include/revision.h
@@ -9,5 +9,5 @@
 // source have to figure out how to create revision.h just to get a build
 // going.  However, if it is not updated, it can be a version behind.
 
-#define GLSLANG_REVISION "24330"
-#define GLSLANG_DATE     "2013/12/04 09:43:00"
+#define GLSLANG_REVISION "24331"
+#define GLSLANG_DATE     "2013/12/04 10:23:03"
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index f1cddb540..cb74ed659 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -671,19 +671,20 @@ TIntermTyped* TParseContext::handleDotDereference(TSourceLoc loc, TIntermTyped*
 // Handle seeing a function declarator in the grammar.  This is the precursor
 // to recognizing a function prototype or function definition.
 //
-TFunction* TParseContext::handleFunctionDeclarator(TSourceLoc loc, TFunction& function)
+TFunction* TParseContext::handleFunctionDeclarator(TSourceLoc loc, TFunction& function, bool prototype)
 {
     // ES can't declare prototypes inside functions
     if (! symbolTable.atGlobalLevel())
         requireProfile(loc, ~EEsProfile, "local function declaration");
 
     //
-    // Multiple declarations of the same function are allowed.
+    // Multiple declarations of the same function name 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 (full prototype match) are allowed.  But, return types and parameter qualifiers must match.
+    // Redeclarations (full signature match) are allowed.  But, return types and parameter qualifiers must also match.
+    //  - except ES 100, which only allows a single prototype
     //
     // ES 100 does not allow redefining, but does allow overloading of built-in functions.
     // ES 300 does not allow redefining or overloading of built-in functions.
@@ -694,9 +695,10 @@ TFunction* TParseContext::handleFunctionDeclarator(TSourceLoc loc, TFunction& fu
         requireProfile(loc, ~EEsProfile, "redefinition of built-in function");
     const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0;
     if (prevDec) {
-        if (prevDec->getType() != function.getType()) {
+        if (prevDec->isPrototyped() && prototype)
+            profileRequires(loc, EEsProfile, 300, 0, "multiple prototypes for same function");
+        if (prevDec->getType() != function.getType())
             error(loc, "overloaded functions must have the same return type", function.getType().getBasicTypeString().c_str(), "");
-        }
         for (int i = 0; i < prevDec->getParamCount(); ++i) {
             if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage)
                 error(loc, "overloaded functions must have the same parameter storage qualifiers for argument", function[i].type->getStorageQualifierString(), "%d", i+1);
@@ -708,16 +710,26 @@ TFunction* TParseContext::handleFunctionDeclarator(TSourceLoc loc, TFunction& fu
 
     arrayObjectCheck(loc, function.getType(), "array in function return type");
 
-    // All built-in functions are defined, even though they don't have a body.
-    if (symbolTable.atBuiltInLevel())
-        function.setDefined();
+    if (prototype) {
+        // All built-in functions are defined, even though they don't have a body.
+        // Count their prototype as a definition instead.
+        if (symbolTable.atBuiltInLevel())
+            function.setDefined();
+        else {
+            if (prevDec && ! builtIn)                
+                symbol->getAsFunction()->setPrototyped();  // need a writable one, but like having prevDec as a const
+            function.setPrototyped();
+        }
+    }
 
+    // This insert won't actually insert it if it's a duplicate signature, but it will still check for
+    // other forms of name collisions.
     if (! symbolTable.insert(function))
-        error(loc, "redeclaration of existing name", function.getName().c_str(), "");
+        error(loc, "function name is redeclaration of existing name", function.getName().c_str(), "");
 
     //
     // If this is a redeclaration, it could also be a definition,
-    // in which case, we want to use the variable names from this one, and not the one that's
+    // in which case, we need to use the parameter names from this one, and not the one that's
     // being redeclared.  So, pass back this declaration, not the one in the symbol table.
     //
     return &function;
diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h
index 69044b110..2df405701 100644
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -88,7 +88,7 @@ public:
     void checkInputArrayConsistency(TSourceLoc, bool tailOnly = false);
     void checkInputArrayConsistency(TSourceLoc, TLayoutGeometry, TType&, const TString&);
     TIntermTyped* handleDotDereference(TSourceLoc, TIntermTyped* base, TString& field);
-    TFunction* handleFunctionDeclarator(TSourceLoc loc, TFunction& function);
+    TFunction* handleFunctionDeclarator(TSourceLoc loc, TFunction& function, bool prototype);
     TIntermAggregate* handleFunctionDefinition(TSourceLoc, TFunction&);
     TIntermTyped* handleFunctionCall(TSourceLoc, TFunction*, TIntermNode*, TIntermAggregate*);
     void nonOpBuiltInCheck(TSourceLoc, const TFunction&, TIntermAggregate&);
diff --git a/glslang/MachineIndependent/SymbolTable.cpp b/glslang/MachineIndependent/SymbolTable.cpp
index 6a7032491..9c18a7a3e 100644
--- a/glslang/MachineIndependent/SymbolTable.cpp
+++ b/glslang/MachineIndependent/SymbolTable.cpp
@@ -286,6 +286,7 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
     mangledName = copyOf.mangledName;
     op = copyOf.op;
     defined = copyOf.defined;
+    prototyped = copyOf.prototyped;
 }
 
 TFunction* TFunction::clone() const
diff --git a/glslang/MachineIndependent/SymbolTable.h b/glslang/MachineIndependent/SymbolTable.h
index bd1a5c9c9..71f07f5c1 100644
--- a/glslang/MachineIndependent/SymbolTable.h
+++ b/glslang/MachineIndependent/SymbolTable.h
@@ -194,12 +194,12 @@ public:
     explicit TFunction(TOperator o) :
         TSymbol(0),
         op(o),
-        defined(false) { }
+        defined(false), prototyped(false) { }
     TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull) :
         TSymbol(name),
         mangledName(*name + '('),
         op(tOp),
-        defined(false) { returnType.shallowCopy(retType); }    
+        defined(false), prototyped(false) { returnType.shallowCopy(retType); }    
 	virtual TFunction* clone() const;
 	virtual ~TFunction();
 
@@ -220,6 +220,8 @@ public:
     virtual TOperator getBuiltInOp() const { return op; }
     virtual void setDefined() { assert(writable); defined = true; }
     virtual bool isDefined() const { return defined; }
+    virtual void setPrototyped() { assert(writable); prototyped = true; }
+    virtual bool isPrototyped() const { return prototyped; }
 
     virtual int getParamCount() const { return static_cast<int>(parameters.size()); }
     virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; }
@@ -237,6 +239,7 @@ protected:
     TString mangledName;
     TOperator op;
     bool defined;
+    bool prototyped;
 };
 
 class TAnonMember : public TSymbol {
diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y
index 3b21c6f13..087d7ebef 100644
--- a/glslang/MachineIndependent/glslang.y
+++ b/glslang/MachineIndependent/glslang.y
@@ -748,6 +748,7 @@ constant_expression
 
 declaration
     : function_prototype SEMICOLON {
+        parseContext.handleFunctionDeclarator($1.loc, *$1.function, true /* prototype */);
         $$ = 0;
         // TODO: 4.0 functionality: subroutines: make the identifier a user type for this signature
     }
@@ -820,7 +821,7 @@ identifier_list
 
 function_prototype
     : function_declarator RIGHT_PAREN  {
-        $$.function = parseContext.handleFunctionDeclarator($2.loc, *$1);
+        $$.function = $1;
         $$.loc = $2.loc;
     }
     ;
@@ -2389,6 +2390,7 @@ external_declaration
 
 function_definition
     : function_prototype {
+        $1.function = parseContext.handleFunctionDeclarator($1.loc, *$1.function, false /* not prototype */);
         $1.intermAggregate = parseContext.handleFunctionDefinition($1.loc, *$1.function);
     }
     compound_statement_no_new_scope {
-- 
GitLab