Improve robustness of extension checking, and its intersection with ES 100 features.
authorJohn Kessenich <cepheus@frii.com>
Fri, 4 Oct 2013 21:09:36 +0000 (21:09 +0000)
committerJohn Kessenich <cepheus@frii.com>
Fri, 4 Oct 2013 21:09:36 +0000 (21:09 +0000)
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23388 e7fa87d3-cd2b-0410-9028-fcbf551c1848

13 files changed:
Test/100.frag [new file with mode: 0644]
Test/array100.frag
Test/baseResults/100.frag.out [new file with mode: 0644]
Test/baseResults/array100.frag.out
Test/testlist
glslang/Include/Types.h
glslang/MachineIndependent/Initialize.cpp
glslang/MachineIndependent/Initialize.h
glslang/MachineIndependent/ParseHelper.cpp
glslang/MachineIndependent/ParseHelper.h
glslang/MachineIndependent/Versions.cpp
glslang/MachineIndependent/Versions.h
glslang/MachineIndependent/glslang.y

diff --git a/Test/100.frag b/Test/100.frag
new file mode 100644 (file)
index 0000000..529b360
--- /dev/null
@@ -0,0 +1,45 @@
+#version 100\r
+\r
+int a[3] = { 2, 3, 4, };  // ERROR\r
+\r
+int uint;\r
+\r
+attribute vec4 v[3];     // ERROR\r
+\r
+float f = 2;             // ERROR\r
+\r
+uniform block {          // ERROR\r
+    int x;\r
+};\r
+\r
+void foo(float);\r
+\r
+void main()\r
+{\r
+    foo(3);              // ERROR\r
+    int s = 1 << 4;      // ERROR\r
+    s = 16 >> 2;         // ERROR\r
+    if (a == a);         // ERROR\r
+    int b, c;\r
+    b = c & 4;           // ERROR\r
+    b = c % 4;           // ERROR\r
+    b = c | 4;           // ERROR\r
+    b >>= 2;             // ERROR\r
+    b <<= 2;             // ERROR\r
+    b %= 3;              // ERROR\r
+\r
+    struct S {\r
+        float f;\r
+        float a[10];\r
+    } s1, s2;\r
+\r
+    s1 = s2;             // ERROR\r
+    if (s1 == s2);       // ERROR\r
+    if (s1 != s2);       // ERROR\r
+\r
+    switch(b) {          // ERROR\r
+    }\r
+}\r
+\r
+invariant gl_FragColor;\r
+float fa[];              // ERROR\r
index 6f0feb4..596e41b 100644 (file)
@@ -21,7 +21,7 @@ void main()
         gu[2] = 4.0;  // ERROR, overflow
     }
 
-    g4 = foo(g5);
+    g4 = foo(g5);  // ERROR
     g5 = g4;  // ERROR
     gu = g4;  // ERROR
 
diff --git a/Test/baseResults/100.frag.out b/Test/baseResults/100.frag.out
new file mode 100644 (file)
index 0000000..fc1369d
--- /dev/null
@@ -0,0 +1,100 @@
+ERROR: 0:3: '{ } style initializers' : not supported with this profile: es\r
+ERROR: 0:3: 'initializer' : not supported for this version or the enabled extensions \r
+ERROR: 0:3: '=' :  cannot convert from 'const int' to '3-element array of mediump int'\r
+ERROR: 0:7: 'attribute' : not supported in this stage: fragment\r
+ERROR: 0:7: 'float' : type requires declaration of default precision qualifier \r
+ERROR: 0:9: '=' :  cannot convert from 'const int' to 'mediump float'\r
+ERROR: 0:11: 'uniform block' : not supported for this version or the enabled extensions \r
+ERROR: 0:19: 'foo' : no matching overloaded function found \r
+ERROR: 0:20: 'bit shift left' : not supported for this version or the enabled extensions \r
+ERROR: 0:21: 'bit shift right' : not supported for this version or the enabled extensions \r
+ERROR: 0:22: 'array comparison' : not supported for this version or the enabled extensions \r
+ERROR: 0:24: 'bitwise and' : not supported for this version or the enabled extensions \r
+ERROR: 0:25: '%' : not supported for this version or the enabled extensions \r
+ERROR: 0:26: 'bitwise inclusive or' : not supported for this version or the enabled extensions \r
+ERROR: 0:27: 'bit-shift right assign' : not supported for this version or the enabled extensions \r
+ERROR: 0:28: 'bit-shift left assign' : not supported for this version or the enabled extensions \r
+ERROR: 0:29: '%=' : not supported for this version or the enabled extensions \r
+ERROR: 0:36: 'array assignment' : not supported for this version or the enabled extensions \r
+ERROR: 0:37: 'array comparison' : not supported for this version or the enabled extensions \r
+ERROR: 0:38: 'array comparison' : not supported for this version or the enabled extensions \r
+ERROR: 0:40: 'switch' : Reserved word. \r
+ERROR: 0:40: 'switch statements' : not supported for this version or the enabled extensions \r
+ERROR: 0:45: '' : array size required \r
+ERROR: 23 compilation errors.  No code generated.\r
+\r
+ERROR: node is still EOpNull!\r
+0:17  Function Definition: main( (void)\r
+0:17    Function Parameters: \r
+0:19    Sequence\r
+0:19      Constant:\r
+0:19        0.000000\r
+0:20      Sequence\r
+0:20        move second child to first child (mediump int)\r
+0:20          's' (mediump int)\r
+0:20          Constant:\r
+0:20            16 (const int)\r
+0:21      move second child to first child (mediump int)\r
+0:21        's' (mediump int)\r
+0:21        Constant:\r
+0:21          4 (const int)\r
+0:22      Test condition and select (void)\r
+0:22        Condition\r
+0:22        Compare Equal (bool)\r
+0:22          'a' (3-element array of mediump int)\r
+0:22          'a' (3-element array of mediump int)\r
+0:22        true case is null\r
+0:24      move second child to first child (mediump int)\r
+0:24        'b' (mediump int)\r
+0:24        bitwise and (mediump int)\r
+0:24          'c' (mediump int)\r
+0:24          Constant:\r
+0:24            4 (const int)\r
+0:25      move second child to first child (mediump int)\r
+0:25        'b' (mediump int)\r
+0:25        mod (mediump int)\r
+0:25          'c' (mediump int)\r
+0:25          Constant:\r
+0:25            4 (const int)\r
+0:26      move second child to first child (mediump int)\r
+0:26        'b' (mediump int)\r
+0:26        inclusive-or (mediump int)\r
+0:26          'c' (mediump int)\r
+0:26          Constant:\r
+0:26            4 (const int)\r
+0:27      right shift second child into first child (mediump int)\r
+0:27        'b' (mediump int)\r
+0:27        Constant:\r
+0:27          2 (const int)\r
+0:28      left shift second child into first child (mediump int)\r
+0:28        'b' (mediump int)\r
+0:28        Constant:\r
+0:28          2 (const int)\r
+0:29      mod second child into first child (mediump int)\r
+0:29        'b' (mediump int)\r
+0:29        Constant:\r
+0:29          3 (const int)\r
+0:36      move second child to first child (structure)\r
+0:36        's1' (structure)\r
+0:36        's2' (structure)\r
+0:37      Test condition and select (void)\r
+0:37        Condition\r
+0:37        Compare Equal (bool)\r
+0:37          's1' (structure)\r
+0:37          's2' (structure)\r
+0:37        true case is null\r
+0:38      Test condition and select (void)\r
+0:38        Condition\r
+0:38        Compare Not Equal (bool)\r
+0:38          's1' (structure)\r
+0:38          's2' (structure)\r
+0:38        true case is null\r
+0:40      'b' (mediump int)\r
+0:?   Linker Objects\r
+0:?     'a' (3-element array of mediump int)\r
+0:?     'uint' (mediump int)\r
+0:?     'v' (smooth in 3-element array of mediump 4-component vector of float)\r
+0:?     'f' (mediump float)\r
+0:?     '__anon__0' (layout(shared ) uniform block)\r
+0:?     'fa' (unsized array of mediump float)\r
+\r
index 05b5797..ce9072b 100644 (file)
@@ -4,14 +4,18 @@ ERROR: 0:9: 'arrayed type' : not supported for this version or the enabled exten
 ERROR: 0:9: 'arrayed type' : not supported for this version or the enabled extensions \r
 ERROR: 0:11: 'arrayed constructor' : not supported for this version or the enabled extensions \r
 ERROR: 0:21: '[' :  array index out of range '2'\r
+ERROR: 0:24: 'array assignment' : not supported for this version or the enabled extensions \r
+ERROR: 0:25: 'array assignment' : not supported for this version or the enabled extensions \r
 ERROR: 0:25: 'assign' :  cannot convert from '4-element array of mediump float' to '5-element array of mediump float'\r
+ERROR: 0:26: 'array assignment' : not supported for this version or the enabled extensions \r
 ERROR: 0:26: 'assign' :  cannot convert from '4-element array of mediump float' to 'unsized array of mediump float'\r
 ERROR: 0:28: 'foo' : no matching overloaded function found \r
 ERROR: 0:31: 'arrayed constructor' : not supported for this version or the enabled extensions \r
+ERROR: 0:31: 'array comparison' : not supported for this version or the enabled extensions \r
 ERROR: 0:35: '[' :  array index out of range '5'\r
 ERROR: 0:38: '[' :  array index out of range '1000'\r
 ERROR: 0:39: '[' :  array index out of range '-1'\r
-ERROR: 13 compilation errors.  No code generated.\r
+ERROR: 17 compilation errors.  No code generated.\r
 \r
 ERROR: node is still EOpNull!\r
 0:9  Function Definition: foo(f1[5]; (4-element array of mediump float)\r
@@ -86,9 +90,9 @@ ERROR: node is still EOpNull!
 0:35          5.000000\r
 0:36      Function Call: foo(f1[5]; (4-element array of mediump float)\r
 0:36        'u' (5-element array of mediump float)\r
-0:38      move second child to first child (4-component vector of float)\r
-0:38        direct index (fragColor 4-component vector of float)\r
-0:38          'gl_FragData' (fragColor 32-element array of 4-component vector of float)\r
+0:38      move second child to first child (mediump 4-component vector of float)\r
+0:38        direct index (fragColor mediump 4-component vector of float)\r
+0:38          'gl_FragData' (fragColor 32-element array of mediump 4-component vector of float)\r
 0:38          Constant:\r
 0:38            1000 (const int)\r
 0:38        Constant:\r
@@ -96,9 +100,9 @@ ERROR: node is still EOpNull!
 0:38          1.000000\r
 0:38          1.000000\r
 0:38          1.000000\r
-0:39      move second child to first child (4-component vector of float)\r
-0:39        direct index (fragColor 4-component vector of float)\r
-0:39          'gl_FragData' (fragColor 32-element array of 4-component vector of float)\r
+0:39      move second child to first child (mediump 4-component vector of float)\r
+0:39        direct index (fragColor mediump 4-component vector of float)\r
+0:39          'gl_FragData' (fragColor 32-element array of mediump 4-component vector of float)\r
 0:39          Constant:\r
 0:39            -1 (const int)\r
 0:39        Constant:\r
@@ -106,9 +110,9 @@ ERROR: node is still EOpNull!
 0:39          1.000000\r
 0:39          1.000000\r
 0:39          1.000000\r
-0:40      move second child to first child (4-component vector of float)\r
-0:40        direct index (fragColor 4-component vector of float)\r
-0:40          'gl_FragData' (fragColor 32-element array of 4-component vector of float)\r
+0:40      move second child to first child (mediump 4-component vector of float)\r
+0:40        direct index (fragColor mediump 4-component vector of float)\r
+0:40          'gl_FragData' (fragColor 32-element array of mediump 4-component vector of float)\r
 0:40          Constant:\r
 0:40            3 (const int)\r
 0:40        Constant:\r
index 31cfa75..8df4088 100644 (file)
@@ -7,6 +7,7 @@ versionsClean.frag
 versionsClean.vert
 versionsErrors.frag
 versionsErrors.vert
+100.frag
 120.vert
 120.frag
 130.frag
index 5a2c9c6..11e43a2 100644 (file)
@@ -580,6 +580,18 @@ public:
 
        virtual bool isMatrix() const { return matrixCols ? true : false; }
     virtual bool isArray() const  { return arraySizes != 0; }
+    virtual bool containsArray() const
+    {
+        if (isArray())
+            return true;
+               if (! structure)
+            return false;
+               for (unsigned int i = 0; i < structure->size(); ++i) {
+            if ((*structure)[i].type->containsArray())
+                return true;
+        }
+        return false;
+    }
     int getArraySize() const { return arraySizes->sizes.front(); }
     void setArraySizes(TArraySizes* s) 
     {
index f26dc31..ed94754 100644 (file)
 //
 
 //
-// Create strings that declare built-in definitions, add built-ins that
-// cannot be expressed in the files, and establish mappings between
+// Create strings that declare built-in definitions, add built-ins programmatically 
+// that cannot be expressed in the strings, and establish mappings between
 // built-in functions and operators.
 //
+// Where to put a built-in:
+//   TBuiltIns::initialize(version,profile)       context-independent textual built-ins; add them to the right string
+//   TBuiltIns::initialize(resources,...)         context-dependent textual built-ins; add them to the right string
+//   IdentifyBuiltIns(...,symbolTable)            context-independent programmatic additions/mappings to the symbol table
+//   IdentifyBuiltIns(...,symbolTable, resources) context-dependent programmatic additions/mappings to the symbol table
+//
 
 #include "../Include/intermediate.h"
 #include "Initialize.h"
@@ -50,14 +56,16 @@ const bool ForwardCompatibility = false;
 
 TBuiltIns::TBuiltIns()
 {
+    // Set up textual representations for making all the permutations
+    // of texturing/imaging functions.
     prefixes[EbtFloat] =  "";
     prefixes[EbtInt]   = "i";
     prefixes[EbtUint]  = "u";
-
     postfixes[2] = "2";
     postfixes[3] = "3";
     postfixes[4] = "4";
 
+    // Map from symbolic class of texturing dimension to numeric dimensions.
     dimMap[Esd1D] = 1;
     dimMap[Esd2D] = 2;
     dimMap[EsdRect] = 2;
@@ -70,14 +78,16 @@ TBuiltIns::~TBuiltIns()
 {
 }
 
+//
+// Add all context-independent built-in functions and variables that are present
+// for the given version and profile.  Share common ones across stages, otherwise
+// make stage-specific entries.
+//
+// Most built-ins variables can be added as simple text strings.  Some need to
+// be added programmatically, which is done later in IdentifyBuiltIns() below.
+//
 void TBuiltIns::initialize(int version, EProfile profile)
 {
-    // TODO: Performance/Memory: consider an extra outer scope for built-ins common across all stages
-
-    //
-    // Initialize all the built-in strings for parsing.
-    //
-
     {
         //============================================================================
         //
@@ -1011,6 +1021,10 @@ void TBuiltIns::initialize(int version, EProfile profile)
     //printf("%s\n", commonBuiltins.c_str();
 }
 
+//
+// Helper function for initialize(), to add the second set of names for texturing, 
+// when adding context-independent built-in functions.
+//
 void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile)
 {
     TBasicType bTypes[3] = { EbtFloat, EbtInt, EbtUint };
@@ -1081,6 +1095,10 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile)
     }
 }
 
+//
+// Helper function for add2ndGenerationSamplingImaging(), 
+// when adding context-independent built-in functions.
+//
 void TBuiltIns::addQueryFunctions(TSampler sampler, TString& typeName, int version, EProfile profile)
 {
     //
@@ -1109,15 +1127,21 @@ void TBuiltIns::addQueryFunctions(TSampler sampler, TString& typeName, int versi
         s.append(",int);\n");
     else
         s.append(");\n");
-
-    // TODO: 4.2 Functionality: imaging functions
 }
 
+//
+// Helper function for add2ndGenerationSamplingImaging(), 
+// when adding context-independent built-in functions.
+//
 void TBuiltIns::addImageFunctions(TSampler sampler, TString& typeName, int version, EProfile profile)
 {
     // TODO: 4.2 Functionality: imaging functions
 }
 
+//
+// Helper function for add2ndGenerationSamplingImaging(), 
+// when adding context-independent built-in functions.
+//
 void TBuiltIns::addSamplingFunctions(TSampler sampler, TString& typeName, int version, EProfile profile)
 {
     // make one string per stage to contain all functions of the passed-in type for that stage
@@ -1297,6 +1321,11 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, TString& typeName, int ve
     }
 }
 
+//
+// Add context-dependent built-in functions and variables that are present
+// for the given version and profile.  Share common ones across stages, otherwise
+// make stage-specific entries.
+//
 void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProfile profile, EShLanguage language)
 {
     //
@@ -1448,6 +1477,12 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf
     }
 }
 
+//
+// Finish adding/processing context-independent built-in symbols.
+// 1) Programmatically add symbols that could not be added by simple text strings above.
+// 2) Map built-in functions to operators, for those that will turn into an operation node
+//    instead of remaining a function call.
+//
 void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymbolTable& symbolTable)
 {
     TPrecisionQualifier pq;
@@ -1643,11 +1678,13 @@ void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymb
     }
 }
 
+//
+// Add context-dependent (resource-specific) built-ins not yet handled.  These
+// would be ones that need to be programmatically added because they cannot 
+// be added by simple text strings.
+//
 void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources)
 {
-    //
-    // Set resource-specific built-ins not yet handled.
-    //
     switch(language) {
 
     case EShLangFragment:
index 661b98c..2b0c6b0 100644 (file)
 
 namespace glslang {
 
+//
+// This is made to hold parseable strings for almost all the built-in
+// functions and variables for one specific combination of version
+// and profile.  (Some still need to be added programmatically.)
+//
+// The strings are organized by
+//    commonBuiltins:  intersection of all stages' built-ins, processed just once
+//    stageBuiltins[]: anything a stage needs that's not in commonBuiltins
+//
 class TBuiltIns {
 public:
     POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
@@ -64,7 +73,8 @@ protected:
     TString commonBuiltins;
     TString stageBuiltins[EShLangCount];
 
-    // Helpers for making text
+    // Helpers for making textual representations of the permutations
+    // of texturing/imaging functions.
     const char* postfixes[5];
     const char* prefixes[EbtNumTypes];
     int dimMap[EsdNumDims];
index fe884bf..9725ff2 100644 (file)
@@ -527,7 +527,8 @@ TIntermTyped* TParseContext::handleDotDereference(TSourceLoc loc, TIntermTyped*
         //
 
         if (field == "length") {
-            profileRequires(loc, ENoProfile, 120, "GL_3DL_array_objects", ".length");
+            profileRequires(loc, ENoProfile, 120, GL_3DL_array_objects, ".length");
+            profileRequires(loc, EEsProfile, 300, 0, ".length");
             result = intermediate.addMethod(base, TType(EbtInt), &field, loc);
         } else
             error(loc, "only the length method is supported for array", field.c_str(), "");
@@ -851,8 +852,8 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
 TFunction* TParseContext::handleConstructorCall(TSourceLoc loc, TPublicType& publicType)
 {
     if (publicType.arraySizes) {
-        profileRequires(loc, ENoProfile, 120, "GL_3DL_array_objects", "arrayed constructor");
-        profileRequires(loc, EEsProfile, 300, "GL_3DL_array_objects", "arrayed constructor");
+        profileRequires(loc, ENoProfile, 120, GL_3DL_array_objects, "arrayed constructor");
+        profileRequires(loc, EEsProfile, 300, 0, "arrayed constructor");
     }
 
     publicType.qualifier.precision = EpqNone;
@@ -1648,8 +1649,10 @@ void TParseContext::arraySizeCheck(TSourceLoc loc, TIntermTyped* expr, int& size
 //
 bool TParseContext::arrayQualifierError(TSourceLoc loc, const TQualifier& qualifier)
 {
-    if (qualifier.storage == EvqConst)
-        profileRequires(loc, ENoProfile, 120, "GL_3DL_array_objects", "const array");
+    if (qualifier.storage == EvqConst) {
+        profileRequires(loc, ENoProfile, 120, GL_3DL_array_objects, "const array");
+        profileRequires(loc, EEsProfile, 300, 0, "const array");
+    }
 
     if (qualifier.storage == EvqVaryingIn && language == EShLangVertex) {
         requireProfile(loc, ~EEsProfile, "vertex input arrays");
@@ -1893,6 +1896,15 @@ void TParseContext::nestedStructCheck(TSourceLoc loc)
     ++structNestingLevel;
 }
 
+void TParseContext::arrayObjectCheck(TSourceLoc loc, const TType& type, const char* op)
+{
+    // Some versions don't allow comparing arrays or structures containing arrays
+    if (type.containsArray()) {
+        profileRequires(loc, ENoProfile, 120, GL_3DL_array_objects, op);
+        profileRequires(loc, EEsProfile, 300, 0, op);
+    }
+}
+
 //
 // Layout qualifier stuff.
 //
@@ -2020,8 +2032,10 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier,
             declareArray(loc, identifier, type, variable, newDeclaration);
         }
 
-        if (initializer)
-            profileRequires(loc, ENoProfile, 120, "GL_3DL_array_objects", "initializer");
+        if (initializer) {
+            profileRequires(loc, ENoProfile, 120, GL_3DL_array_objects, "initializer");
+            profileRequires(loc, EEsProfile, 300, 0, "initializer");
+        }
     } else {
         // non-array case
         if (! variable)
index 4c3f75b..1d874ff 100644 (file)
@@ -115,6 +115,7 @@ public:
     void paramCheck(TSourceLoc, TStorageQualifier qualifier, TType* type);
     void nestedBlockCheck(TSourceLoc);
     void nestedStructCheck(TSourceLoc);
+    void arrayObjectCheck(TSourceLoc, const TType&, const char* op);
 
     void setLayoutQualifier(TSourceLoc, TPublicType&, TString&);
     void setLayoutQualifier(TSourceLoc, TPublicType&, TString&, int);
@@ -161,7 +162,6 @@ public:
 
 protected:
     const char* getPreamble();
-    TExtensionBehavior getExtensionBehavior(const char* behavior);
     void nonInitConstCheck(TSourceLoc, TString& identifier, TType& type);
     TVariable* declareNonArray(TSourceLoc, TString& identifier, TType&, bool& newDeclaration);
     void declareArray(TSourceLoc, TString& identifier, const TType&, TVariable*&, bool& newDeclaration);
index 0afd7fd..aa6fc52 100644 (file)
@@ -48,7 +48,7 @@
 // To add a new hypothetical "Feature F" to the front end, where an extension
 // "XXX_extension_X" can be used to enable the feature, do the following.
 // 
-// 1) Understand that specific features are what are error-checked for, not
+// OVERVIEW: Specific features are what are error-checked for, not
 //    extensions:  A specific Feature F might be enabled by an extension, or a 
 //    particular version in a particular profile, or a stage, or combinations, etc.
 //    
 //    will then always continue as if the tested feature was enabled.
 //    
 //    There is typically no if-testing or conditional parsing, just insertion of requirements.
+//    However, if symbols specific to the extension are added (step 5), they will
+//    only be added under tests that the minimum version and profile are present.
+//
+// 1) Add a symbol name for the extension string at the bottom of Versions.h:
+//
+//     const char* const XXX_extension_X = "XXX_extension_X";
 // 
 // 2) Add extension initialization to TParseContext::initializeExtensionBehavior(),
 //    the first function below:
 // 
-//     extensionBehavior["XXX_extension_X"] = EBhDisable;
+//     extensionBehavior[XXX_extension_X] = EBhDisable;
 // 
 // 3) Insert a profile check in the feature's path (unless all profiles support the feature,
 //    for some version level).  That is, call requireProfile() to constrain the profiles, e.g.:
@@ -90,7 +96,7 @@
 //        profileRequires(loc, 
 //                        ECoreProfile | ECompatibilityProfile,
 //                        420, // 0 if no version incorporated the feature into the core spec.
-//                        "XXX_extension_X", // can be a list of extensions that all add the feature
+//                        XXX_extension_X, // can be a list of extensions that all add the feature
 //                        "Feature F");
 // 
 //    This allows the feature if either A) one of the extensions is enabled or
 // 
 //        ~EEsProfile
 //
+// 5) If built-in symbols are added by the extension, add them in Initialize.cpp; see
+//    the comment at the top of that file for where to put them.
+//
 
 #include "ParseHelper.h"
 
@@ -129,10 +138,14 @@ namespace glslang {
 //
 void TParseContext::initializeExtensionBehavior()
 {
-    extensionBehavior["GL_ARB_texture_rectangle"] = EBhDisable;
-    extensionBehavior["GL_3DL_array_objects"] = EBhDisable;
+    extensionBehavior[GL_ARB_texture_rectangle] = EBhDisable;
+    extensionBehavior[GL_3DL_array_objects] = EBhDisable;
+    extensionBehavior[GL_ARB_shading_language_420pack] = EBhDisable;
 }
 
+//
+// Map from profile enum to externally readable text name.
+//
 const char* ProfileName(EProfile profile)
 {
     switch (profile) {
@@ -159,6 +172,9 @@ void TParseContext::requireProfile(TSourceLoc loc, int profileMask, const char *
         error(loc, "not supported with this profile:", featureDesc, ProfileName(profile));
 }
 
+//
+// Map from stage enum to externally readable text name.
+//
 const char* StageName(EShLanguage stage) 
 {
     switch(stage) {
@@ -274,32 +290,27 @@ void TParseContext::requireNotRemoved(TSourceLoc loc, int profileMask, int remov
 }
 
 //
-// Translate from text string of extension's behavior to enum.
+// Change the current state of an extension's behavior.
 //
-TExtensionBehavior TParseContext::getExtensionBehavior(const char* behavior)
-{
-    if (! strcmp("require", behavior))
-        return EBhRequire;
-    else if (! strcmp("enable", behavior))
-        return EBhEnable;
-    else if (! strcmp("disable", behavior))
-        return EBhDisable;
-    else if (! strcmp("warn", behavior))
-        return EBhWarn;
-    else {
-        error(currentLoc, "behavior not supported", "#extension", behavior);
-        return EBhDisable;
-    }
-}
-
 void TParseContext::updateExtensionBehavior(const char* extName, const char* behaviorString)
 {
-    TExtensionBehavior behavior = getExtensionBehavior(behaviorString);
-    TMap<TString, TExtensionBehavior>:: iterator iter;
-    TString msg;
+    // Translate from text string of extension's behavior to an enum.
+    TExtensionBehavior behavior = EBhDisable;
+    if (! strcmp("require", behaviorString))
+        behavior = EBhRequire;
+    else if (! strcmp("enable", behaviorString))
+        behavior = EBhEnable;
+    else if (! strcmp("disable", behaviorString))
+        behavior = EBhDisable;
+    else if (! strcmp("warn", behaviorString))
+        behavior = EBhWarn;
+    else
+        error(currentLoc, "behavior not supported", "#extension", behaviorString);
 
-    // special case for the 'all' extension
+    // Update the current behavior
+    TMap<TString, TExtensionBehavior>::iterator iter;
     if (! strcmp(extName, "all")) {
+        // special case for the 'all' extension; apply it to every extension present
         if (behavior == EBhRequire || behavior == EBhEnable) {
             error(currentLoc, "extension 'all' cannot have 'require' or 'enable' behavior", "#extension", "");
             return;
@@ -308,6 +319,7 @@ void TParseContext::updateExtensionBehavior(const char* extName, const char* beh
                 iter->second = behavior;
         }
     } else {
+        // Do the update for this single extension
         iter = extensionBehavior.find(TString(extName));
         if (iter == extensionBehavior.end()) {
             switch (behavior) {
index d917b5d..94fd644 100644 (file)
 //
 
 //
-// The behaviors from "#extension extension_name : behavior"
-//
-typedef enum {
-    EBhRequire,
-    EBhEnable,
-    EBhWarn,
-    EBhDisable
-} TExtensionBehavior;
-
-//
 // Profiles are set up for masking operations, so queries can be done on multiple
 // profiles at the same time.
 //
@@ -65,4 +55,26 @@ typedef enum {
     EEsProfile            = (1 << 3)
 } EProfile;
 
+namespace glslang {
+
+//
+// The behaviors from the GLSL "#extension extension_name : behavior"
+//
+typedef enum {
+    EBhRequire,
+    EBhEnable,
+    EBhWarn,
+    EBhDisable
+} TExtensionBehavior;
+
+//
+// Symbolic names for extensions.  Strings may be directly used when calling the
+// functions, but better to have the compiler do spelling checks.
+//
+const char* const GL_ARB_texture_rectangle        = "GL_ARB_texture_rectangle";
+const char* const GL_3DL_array_objects            = "GL_3DL_array_objects";
+const char* const GL_ARB_shading_language_420pack = "GL_ARB_shading_language_420pack";
+
+} // end namespace glslang
+
 #endif // _VERSIONS_INCLUDED_
index 9496e27..17f3b27 100644 (file)
@@ -463,6 +463,7 @@ multiplicative_expression
         }\r
     }\r
     | multiplicative_expression PERCENT unary_expression {\r
+        parseContext.fullIntegerCheck($2.loc, "%");\r
         $$ = parseContext.intermediate.addBinaryMath(EOpMod, $1, $3, $2.loc);\r
         if ($$ == 0) {\r
             parseContext.binaryOpError($2.loc, "%", $1->getCompleteString(), $3->getCompleteString());\r
@@ -552,24 +553,24 @@ relational_expression
 equality_expression\r
     : relational_expression { $$ = $1; }\r
     | equality_expression EQ_OP relational_expression  {\r
+        parseContext.arrayObjectCheck($2.loc, $1->getType(), "array comparison");\r
         $$ = parseContext.intermediate.addBinaryMath(EOpEqual, $1, $3, $2.loc);\r
         if ($$ == 0) {\r
             parseContext.binaryOpError($2.loc, "==", $1->getCompleteString(), $3->getCompleteString());\r
             TConstUnionArray unionArray(1);\r
             unionArray[0].setBConst(false);\r
             $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.loc);\r
-        } else if (($1->isArray() || $3->isArray()))\r
-            parseContext.profileRequires($2.loc, ENoProfile, 120, "GL_3DL_array_objects", "==");\r
+        }\r
     }\r
     | equality_expression NE_OP relational_expression {\r
+        parseContext.arrayObjectCheck($2.loc, $1->getType(), "array comparison");\r
         $$ = parseContext.intermediate.addBinaryMath(EOpNotEqual, $1, $3, $2.loc);\r
         if ($$ == 0) {\r
             parseContext.binaryOpError($2.loc, "!=", $1->getCompleteString(), $3->getCompleteString());\r
             TConstUnionArray unionArray(1);\r
             unionArray[0].setBConst(false);\r
             $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.loc);\r
-        } else if (($1->isArray() || $3->isArray()))\r
-            parseContext.profileRequires($2.loc, ENoProfile, 120, "GL_3DL_array_objects", "!=");\r
+        }\r
     }\r
     ;\r
 \r
@@ -664,23 +665,42 @@ conditional_expression
 assignment_expression\r
     : conditional_expression { $$ = $1; }\r
     | unary_expression assignment_operator assignment_expression {\r
+        parseContext.arrayObjectCheck($2.loc, $1->getType(), "array assignment");\r
         parseContext.lValueErrorCheck($2.loc, "assign", $1);\r
         $$ = parseContext.intermediate.addAssign($2.op, $1, $3, $2.loc);\r
         if ($$ == 0) {\r
             parseContext.assignError($2.loc, "assign", $1->getCompleteString(), $3->getCompleteString());\r
             $$ = $1;\r
-        } else if (($1->isArray() || $3->isArray()))\r
-            parseContext.profileRequires($2.loc, ENoProfile, 120, "GL_3DL_array_objects", "=");\r
+        }\r
     }\r
     ;\r
 \r
 assignment_operator\r
-    : EQUAL        { $$.loc = $1.loc; $$.op = EOpAssign; }\r
-    | MUL_ASSIGN   { $$.loc = $1.loc; $$.op = EOpMulAssign; }\r
-    | DIV_ASSIGN   { $$.loc = $1.loc; $$.op = EOpDivAssign; }\r
-    | MOD_ASSIGN   { $$.loc = $1.loc; $$.op = EOpModAssign; }\r
-    | ADD_ASSIGN   { $$.loc = $1.loc; $$.op = EOpAddAssign; }\r
-    | SUB_ASSIGN   { $$.loc = $1.loc; $$.op = EOpSubAssign; }\r
+    : EQUAL {\r
+        $$.loc = $1.loc;\r
+        $$.op = EOpAssign;\r
+    }\r
+    | MUL_ASSIGN {\r
+        $$.loc = $1.loc; \r
+        $$.op = EOpMulAssign;\r
+    }\r
+    | DIV_ASSIGN {\r
+        $$.loc = $1.loc; \r
+        $$.op = EOpDivAssign;\r
+    }\r
+    | MOD_ASSIGN   {        \r
+        parseContext.fullIntegerCheck($1.loc, "%=");\r
+        $$.loc = $1.loc; \r
+        $$.op = EOpModAssign;\r
+    }\r
+    | ADD_ASSIGN {\r
+        $$.loc = $1.loc; \r
+        $$.op = EOpAddAssign;\r
+    }\r
+    | SUB_ASSIGN {\r
+        $$.loc = $1.loc;\r
+        $$.op = EOpSubAssign;\r
+    }\r
     | LEFT_ASSIGN  {\r
         parseContext.fullIntegerCheck($1.loc, "bit-shift left assign");\r
         $$.loc = $1.loc; $$.op = EOpLeftShiftAssign;\r
@@ -853,7 +873,7 @@ parameter_declarator
     // Type + name\r
     : type_specifier IDENTIFIER {\r
         if ($1.arraySizes) {\r
-            parseContext.profileRequires($1.loc, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type");\r
+            parseContext.profileRequires($1.loc, ENoProfile, 120, GL_3DL_array_objects, "arrayed type");\r
             parseContext.profileRequires($1.loc, EEsProfile, 300, 0, "arrayed type");\r
             parseContext.arraySizeRequiredCheck($1.loc, $1.arraySizes->getSize());\r
         }\r
@@ -868,7 +888,7 @@ parameter_declarator
     }\r
     | type_specifier IDENTIFIER array_specifier {\r
         if ($1.arraySizes) {\r
-            parseContext.profileRequires($1.loc, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type");\r
+            parseContext.profileRequires($1.loc, ENoProfile, 120, GL_3DL_array_objects, "arrayed type");\r
             parseContext.profileRequires($1.loc, EEsProfile, 300, 0, "arrayed type");\r
             parseContext.arraySizeRequiredCheck($1.loc, $1.arraySizes->getSize());\r
         }\r
@@ -989,7 +1009,7 @@ fully_specified_type
         $$ = $1;\r
 \r
         if ($1.arraySizes) {\r
-            parseContext.profileRequires($1.loc, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type");\r
+            parseContext.profileRequires($1.loc, ENoProfile, 120, GL_3DL_array_objects, "arrayed type");\r
             parseContext.profileRequires($1.loc, EEsProfile, 300, 0, "arrayed type");\r
             if (parseContext.profile == EEsProfile)\r
                 parseContext.arraySizeRequiredCheck($1.loc, $1.arraySizes->getSize());\r
@@ -1001,7 +1021,7 @@ fully_specified_type
         parseContext.globalQualifierFix($1.loc, $1.qualifier, $2);\r
 \r
         if ($2.arraySizes) {\r
-            parseContext.profileRequires($2.loc, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type");\r
+            parseContext.profileRequires($2.loc, ENoProfile, 120, GL_3DL_array_objects, "arrayed type");\r
             parseContext.profileRequires($2.loc, EEsProfile, 300, 0, "arrayed type");\r
             if (parseContext.profile == EEsProfile)\r
                 parseContext.arraySizeRequiredCheck($2.loc, $2.arraySizes->getSize());\r
@@ -1676,28 +1696,28 @@ type_specifier_nonarray
         $$.sampler.set(EbtUint, EsdCube, true);\r
     }\r
     | SAMPLER2DRECT {\r
-        parseContext.profileRequires($1.loc, ENoProfile, 140, "GL_ARB_texture_rectangle", "rectangle texture");\r
+        parseContext.profileRequires($1.loc, ENoProfile, 140, GL_ARB_texture_rectangle, "rectangle texture");\r
 \r
         $$.init($1.loc, parseContext.symbolTable.atGlobalLevel());\r
         $$.basicType = EbtSampler;\r
         $$.sampler.set(EbtFloat, EsdRect);\r
     }\r
     | SAMPLER2DRECTSHADOW {\r
-        parseContext.profileRequires($1.loc, ECoreProfile, 140, "GL_ARB_texture_rectangle", "rectangle texture");\r
+        parseContext.profileRequires($1.loc, ECoreProfile, 140, GL_ARB_texture_rectangle, "rectangle texture");\r
 \r
         $$.init($1.loc, parseContext.symbolTable.atGlobalLevel());\r
         $$.basicType = EbtSampler;\r
         $$.sampler.set(EbtFloat, EsdRect, false, true);\r
     }\r
     | ISAMPLER2DRECT {\r
-        parseContext.profileRequires($1.loc, ECoreProfile, 140, "GL_ARB_texture_rectangle", "rectangle texture");\r
+        parseContext.profileRequires($1.loc, ECoreProfile, 140, GL_ARB_texture_rectangle, "rectangle texture");\r
 \r
         $$.init($1.loc, parseContext.symbolTable.atGlobalLevel());\r
         $$.basicType = EbtSampler;\r
         $$.sampler.set(EbtInt, EsdRect);\r
     }\r
     | USAMPLER2DRECT {\r
-        parseContext.profileRequires($1.loc, ECoreProfile, 140, "GL_ARB_texture_rectangle", "rectangle texture");\r
+        parseContext.profileRequires($1.loc, ECoreProfile, 140, GL_ARB_texture_rectangle, "rectangle texture");\r
 \r
         $$.init($1.loc, parseContext.symbolTable.atGlobalLevel());\r
         $$.basicType = EbtSampler;\r
@@ -1992,7 +2012,7 @@ struct_declaration_list
 struct_declaration\r
     : type_specifier struct_declarator_list SEMICOLON {\r
         if ($1.arraySizes) {\r
-            parseContext.profileRequires($1.loc, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type");\r
+            parseContext.profileRequires($1.loc, ENoProfile, 120, GL_3DL_array_objects, "arrayed type");\r
             parseContext.profileRequires($1.loc, EEsProfile, 300, 0, "arrayed type");\r
             if (parseContext.profile == EEsProfile)\r
                 parseContext.arraySizeRequiredCheck($1.loc, $1.arraySizes->getSize());\r
@@ -2010,7 +2030,7 @@ struct_declaration
     }\r
     | type_qualifier type_specifier struct_declarator_list SEMICOLON {\r
         if ($2.arraySizes) {\r
-            parseContext.profileRequires($2.loc, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type");\r
+            parseContext.profileRequires($2.loc, ENoProfile, 120, GL_3DL_array_objects, "arrayed type");\r
             parseContext.profileRequires($2.loc, EEsProfile, 300, 0, "arrayed type");\r
             if (parseContext.profile == EEsProfile)\r
                 parseContext.arraySizeRequiredCheck($2.loc, $2.arraySizes->getSize());\r
@@ -2062,9 +2082,15 @@ initializer
         $$ = $1;\r
     }\r
     | LEFT_BRACE initializer_list RIGHT_BRACE {\r
+        const char* initFeature = "{ } style initializers";\r
+        parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, initFeature);\r
+        parseContext.profileRequires($1.loc, ECoreProfile | ECompatibilityProfile, 420, GL_ARB_shading_language_420pack, initFeature);\r
         $$ = $2;\r
     }\r
     | LEFT_BRACE initializer_list COMMA RIGHT_BRACE {\r
+        const char* initFeature = "{ } style initializers";\r
+        parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, initFeature);\r
+        parseContext.profileRequires($1.loc, ECoreProfile | ECompatibilityProfile, 420, GL_ARB_shading_language_420pack, initFeature);\r
         $$ = $2;\r
     }\r
     ;\r