Simultaneously fix only known memory leak and take the next step in supporting arrays...
authorJohn Kessenich <cepheus@frii.com>
Mon, 11 Feb 2013 00:54:44 +0000 (00:54 +0000)
committerJohn Kessenich <cepheus@frii.com>
Mon, 11 Feb 2013 00:54:44 +0000 (00:54 +0000)
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@20514 e7fa87d3-cd2b-0410-9028-fcbf551c1848

14 files changed:
StandAlone/StandAlone.cpp
Test/array.frag [new file with mode: 0644]
Test/array100.frag [new file with mode: 0644]
Test/testlist
glslang/Include/BaseTypes.h
glslang/Include/Types.h
glslang/MachineIndependent/Initialize.cpp
glslang/MachineIndependent/ParseHelper.cpp
glslang/MachineIndependent/ParseHelper.h
glslang/MachineIndependent/ShaderLang.cpp
glslang/MachineIndependent/SymbolTable.cpp
glslang/MachineIndependent/glslang.l
glslang/MachineIndependent/glslang.y
glslang/MachineIndependent/intermOut.cpp

index 921fddd..38fe213 100644 (file)
@@ -254,6 +254,7 @@ bool CompileFile(char *fileName, ShHandle compiler, int debugOptions, const TBui
 #ifdef MEASURE_MEMORY
 
         GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters));
+        printf("Working set size: %d\n", counters.WorkingSetSize);
     }
 #endif
 
diff --git a/Test/array.frag b/Test/array.frag
new file mode 100644 (file)
index 0000000..090d353
--- /dev/null
@@ -0,0 +1,57 @@
+#version 130
+
+float gu[];
+float g4[4];
+float g5[5];
+
+uniform int a;
+
+float[4] foo(float a[5])
+{
+    return float[](a[0], a[1], a[2], a[3]);
+}
+
+void bar(float[5]) {}
+
+void main()
+{
+    {
+        float gu[2];  // okay, new scope
+
+        gu[2] = 4.0;  // ERROR, overflow
+    }
+
+    gu[2] = 4.0; // okay
+
+    gu[3] = 3.0;
+    gu[a] = 5.0; // ERROR
+
+    g4 = foo(g5);
+    g5 = g4;  // ERROR
+    gu = g4;  // ERROR
+
+    foo(gu);  // ERROR
+    bar(g5);
+
+    if (float[4](1.0, 2.0, 3.0, 4.0) == g4)
+        gu[0] = 2.0;
+
+    float u[];
+    u[2] = 3.0; // okay
+    float u[5];
+    u[5] = 5.0; // ERROR
+    foo(u);     // okay
+
+    gl_FragData[1000] = vec4(1.0); // ERROR
+    gl_FragData[-1] = vec4(1.0);   // ERROR
+    gl_FragData[3] = vec4(1.0);
+
+    const int ca[] = int[](3, 2);
+    int sum = ca[0];
+    sum += ca[1];
+    sum += ca[2];  // ERROR
+
+    const int ca3[3] = int[](3, 2);  // ERROR
+    int ica[] = int[](3, 2);
+    int ica3[3] = int[](3, 2);       // ERROR
+}
diff --git a/Test/array100.frag b/Test/array100.frag
new file mode 100644 (file)
index 0000000..87c125b
--- /dev/null
@@ -0,0 +1,48 @@
+#version 100
+
+float gu[];
+float g4[4];
+float g5[5];
+
+uniform int a;
+
+float[4] foo(float[5] a)  // ERROR  // ERROR
+{
+    return float[](a[0], a[1], a[2], a[3]);  // ERROR
+}
+
+void bar(float[5]) {}
+
+void main()
+{
+    {
+        float gu[2];  // okay, new scope
+
+        gu[2] = 4.0;  // ERROR, overflow
+    }
+
+    gu[2] = 4.0; // okay
+
+    gu[3] = 3.0;
+    gu[a] = 5.0; // ERROR
+
+    g4 = foo(g5);
+    g5 = g4;  // ERROR
+    gu = g4;  // ERROR
+
+    foo(gu);  // ERROR
+    bar(g5);
+
+    if (float[4](1.0, 2.0, 3.0, 4.0) == g4)  // ERROR
+        gu[0] = 2.0;
+
+    float u[];
+    u[2] = 3.0; // okay
+    float u[5];
+    u[5] = 5.0; // ERROR
+    foo(u);     // okay
+
+    gl_FragData[1000] = vec4(1.0); // ERROR
+    gl_FragData[-1] = vec4(1.0);   // ERROR
+    gl_FragData[3] = vec4(1.0);
+}
index 6e88058..afe4f9b 100644 (file)
@@ -17,3 +17,5 @@ cppIndent.vert
 cppNest.vert
 cppComplexExpr.vert
 pointCoord.frag
+array.frag
+array100.frag
\ No newline at end of file
index ef3f910..c22277c 100644 (file)
@@ -104,14 +104,12 @@ enum TStorageQualifier {
     EvqLast,
 };
 
-//
-// This is just for debug print out, carried along with the definitions above.
-//
+// These will show up in error messages
 __inline const char* getStorageQualifierString(TStorageQualifier q) 
 {
     switch (q) {
-    case EvqTemporary:      return "Temporary";      break;
-    case EvqGlobal:         return "Global";         break;
+    case EvqTemporary:      return "temporary";      break;
+    case EvqGlobal:         return "global";         break;
     case EvqConst:          return "const";          break;
     case EvqConstReadOnly:  return "const (read only)"; break;
     case EvqAttribute:      return "attribute";      break;
@@ -121,14 +119,14 @@ __inline const char* getStorageQualifierString(TStorageQualifier q)
     case EvqIn:             return "in";             break;
     case EvqOut:            return "out";            break;
     case EvqInOut:          return "inout";          break;
-    case EvqPosition:       return "Position";       break;
-    case EvqPointSize:      return "PointSize";      break;
-    case EvqClipVertex:     return "ClipVertex";     break;
-    case EvqFace:           return "FrontFacing";    break;
-    case EvqFragCoord:      return "FragCoord";      break;
-    case EvqPointCoord:     return "PointCoord";     break;
-    case EvqFragColor:      return "FragColor";      break;
-    case EvqFragDepth:      return "FragDepth";      break;
+    case EvqPosition:       return "gl_Position";    break;
+    case EvqPointSize:      return "gl_PointSize";   break;
+    case EvqClipVertex:     return "gl_ClipVertex";  break;
+    case EvqFace:           return "gl_FrontFacing"; break;
+    case EvqFragCoord:      return "gl_FragCoord";   break;
+    case EvqPointCoord:     return "gl_PointCoord";  break;
+    case EvqFragColor:      return "fragment out";   break;
+    case EvqFragDepth:      return "gl_FragDepth";   break;
     default:                return "unknown qualifier";
     }
 }
index ab66545..b6eaac9 100644 (file)
@@ -57,6 +57,24 @@ inline TTypeList* NewPoolTTypeList()
 }
 
 //
+// TODO: TArraySizes memory: This could be replaced by something smaller.
+// Almost all arrays could be handled by two sizes each fitting
+// in 16 bits, needing a real vector only in the cases where there
+// are more than 3 sizes or a size needing more than 16 bits.
+//
+// The type is a pointer, so that it can be non-allocated and zero
+// for the vast majority of non-array types.  Note that means if it
+// is used, it will be containing at least one size.
+
+typedef TVector<int>* TArraySizes;
+
+inline TArraySizes NewPoolTArraySizes()
+{
+    void* memory = GlobalPoolAllocator.allocate(sizeof(TVector<int>));
+    return new(memory) TVector<int>;
+}
+
+//
 // This is a workaround for a problem with the yacc stack,  It can't have
 // types that it thinks have non-trivial constructors.  It should
 // just be used while recognizing the grammar, not anything else.  Pointers
@@ -79,9 +97,8 @@ public:
     int vectorSize : 4;
     int matrixCols : 4;
     int matrixRows : 4;
-    bool array;
-    int arraySize;
-    TType* userDef;
+    TArraySizes arraySizes;
+    const TType* userDef;
     int line;
 
     void initType(int ln = 0)
@@ -90,8 +107,7 @@ public:
         vectorSize = 1;
         matrixRows = 0;
         matrixCols = 0;
-        array = false;
-        arraySize = 0;
+        arraySizes = 0;
         userDef = 0;
         line = ln;
     }
@@ -110,6 +126,8 @@ public:
 
     void setVector(int s)
     {
+        matrixRows = 0;
+        matrixCols = 0;
         vectorSize = s;
     }
 
@@ -119,12 +137,6 @@ public:
         matrixCols = c;
         vectorSize = 0;
     }
-
-    void setArray(bool a, int s = 0)
-    {
-        array = a;
-        arraySize = s;
-    }
 };
 
 typedef std::map<TTypeList*, TTypeList*> TStructureMap;
@@ -136,7 +148,7 @@ class TType {
 public:
     POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
     explicit TType(TBasicType t, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0) :
-                            type(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), array(false), arraySize(0),
+                            type(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0),
                             structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0),
                             fieldName(0), mangled(0), typeName(0) 
                             {
@@ -144,7 +156,7 @@ public:
                                 qualifier.precision = EpqNone;
                             }
     explicit TType(const TPublicType &p) :
-                            type(p.type), vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), array(p.array), arraySize(p.arraySize),
+                            type(p.type), vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), arraySizes(p.arraySizes),
                             structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0), typeName(0)
                             {
                                 qualifier = p.qualifier;
@@ -154,7 +166,7 @@ public:
                                 }
                             }
     explicit TType(TTypeList* userDef, const TString& n) :
-                            type(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), array(false), arraySize(0),
+                            type(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), arraySizes(0),
                             structure(userDef), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0) 
                             {
                                 qualifier.storage = EvqTemporary;
@@ -173,9 +185,13 @@ public:
                vectorSize = copyOf.vectorSize;
                matrixCols = copyOf.matrixCols;
                matrixRows = copyOf.matrixRows;
-               array = copyOf.array;
-               arraySize = copyOf.arraySize;
-               
+
+        if (copyOf.arraySizes) {
+            arraySizes = NewPoolTArraySizes();
+            *arraySizes = *copyOf.arraySizes;
+        } else
+            arraySizes = 0;
+
                TStructureMapIterator iter;
                if (copyOf.structure) {
                if ((iter = remapper.find(structure)) == remapper.end()) {
@@ -220,9 +236,8 @@ public:
 
     virtual void dereference()
     {
-        if (array) {
-            array = false;
-            arraySize = 0;
+        if (arraySizes) {
+            arraySizes = 0;
             maxArraySize = 0;
         } else if (matrixCols > 0) {
             vectorSize = matrixRows;
@@ -232,7 +247,7 @@ public:
             vectorSize = 1;
     }
 
-    virtual void setElementType(TBasicType t, int s, int mc, int mr, TType* userDef)
+    virtual void setElementType(TBasicType t, int s, int mc, int mr, const TType* userDef)
     { 
         type = t;
         vectorSize = s;
@@ -265,9 +280,15 @@ public:
     virtual int getMatrixRows() const { return matrixRows; }
 
        virtual bool isMatrix() const { return matrixCols ? true : false; }
-    virtual bool isArray() const  { return array ? true : false; }
-    int getArraySize() const { return arraySize; }
-    void setArraySize(int s) { array = true; arraySize = s; }
+    virtual bool isArray() const  { return arraySizes != 0; }
+    int getArraySize() const { return arraySizes->front(); }
+    void setArraySizes(TArraySizes s) {
+        // copy; we don't want distinct types sharing the same descriptor
+        if (! arraySizes)
+            arraySizes = NewPoolTArraySizes();
+        *arraySizes = *s;
+    }
+    void changeArraySize(int s) { arraySizes->front() = s; }
     void setMaxArraySize (int s) { maxArraySize = s; }
     int getMaxArraySize () const { return maxArraySize; }
     void setArrayInformationType(TType* t) { arrayInformationType = t; }
@@ -336,7 +357,7 @@ public:
                vectorSize == right.vectorSize &&
                matrixCols == right.matrixCols &&
                matrixRows == right.matrixRows &&
-                    array == right.array      && (!array || arraySize == right.arraySize) &&
+              (arraySizes == 0 && right.arraySizes == 0 || (arraySizes && right.arraySizes && *arraySizes == *right.arraySizes)) &&
                 structure == right.structure;
         // don't check the qualifier, it's not ever what's being sought after
     }
@@ -353,10 +374,9 @@ protected:
     int vectorSize       : 4;
     int matrixCols       : 4;
     int matrixRows       : 4;
-       unsigned int array   : 1;
     TQualifier qualifier;
 
-    int arraySize;
+    TArraySizes arraySizes;
 
     TTypeList* structure;      // 0 unless this is a struct
     mutable int structureSize;
index a02f0a3..ad428a7 100644 (file)
@@ -713,7 +713,7 @@ void TBuiltIns::initialize()
 void TBuiltIns::initialize(const TBuiltInResource &resources)
 {
     //
-    // Initialize all the built-in strings for parsing.
+    // Initialize the context-dependent (resource-dependent) built-in strings for parsing.
     //
     TString StandardUniforms;    
 
@@ -939,7 +939,9 @@ void IdentifyBuiltIns(EShLanguage language, TSymbolTable& symbolTable, const TBu
     case EShLangFragment: {
             // Set up gl_FragData.  The array size.
             TType fragData(EbtFloat, EvqFragColor, 4);
-            fragData.setArraySize(resources.maxDrawBuffers);
+            TArraySizes arraySizes = NewPoolTArraySizes();
+            arraySizes->push_back(resources.maxDrawBuffers);
+            fragData.setArraySizes(arraySizes);
             symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"),    fragData));
         }
         break;
index 189d197..8c1ced7 100644 (file)
@@ -571,9 +571,14 @@ bool TParseContext::constructorErrorCheck(int line, TIntermNode* node, TFunction
     if (constType)
         type->getQualifier().storage = EvqConst;
 
-    if (type->isArray() && type->getArraySize() != function.getParamCount()) {
-        error(line, "array constructor needs one argument per array element", "constructor", "");
-        return true;
+    if (type->isArray()) {
+        if (type->getArraySize() == 0) {
+            // auto adapt the constructor type to the number of arguments
+            type->changeArraySize(function.getParamCount());
+        } else if (type->getArraySize() != function.getParamCount()) {
+            error(line, "array constructor needs one argument per array element", "constructor", "");
+            return true;
+        }
     }
 
     if (arrayArg && op != EOpConstructStruct) {
@@ -653,7 +658,7 @@ bool TParseContext::boolErrorCheck(int line, const TIntermTyped* type)
 //
 bool TParseContext::boolErrorCheck(int line, const TPublicType& pType)
 {
-    if (pType.type != EbtBool || pType.array || pType.matrixCols > 1 || (pType.vectorSize > 1)) {
+    if (pType.type != EbtBool || pType.arraySizes || pType.matrixCols > 1 || (pType.vectorSize > 1)) {
         error(line, "boolean expression expected", "", "");
         return true;
     } 
@@ -743,7 +748,7 @@ bool TParseContext::parameterSamplerErrorCheck(int line, TStorageQualifier quali
     return false;
 }
 
-bool TParseContext::containsSampler(TType& type)
+bool TParseContext::containsSampler(const TType& type)
 {
     if (IsSampler(type.getBasicType()))
         return true;
@@ -866,9 +871,6 @@ bool TParseContext::arrayErrorCheck(int line, TString& identifier, TPublicType t
         
         variable = new TVariable(&identifier, TType(type));
 
-        if (type.arraySize)
-            variable->getType().setArraySize(type.arraySize);
-
         if (! symbolTable.insert(*variable)) {
             delete variable;
             error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str(), "");
@@ -897,16 +899,15 @@ bool TParseContext::arrayErrorCheck(int line, TString& identifier, TPublicType t
 
         TType* t = variable->getArrayInformationType();
         while (t != 0) {
-            if (t->getMaxArraySize() > type.arraySize) {
+            if (t->getMaxArraySize() > type.arraySizes->front()) {
                 error(line, "higher index value already used for the array", identifier.c_str(), "");
                 return true;
             }
-            t->setArraySize(type.arraySize);
+            t->setArraySizes(type.arraySizes);
             t = t->getArrayInformationType();
         }
 
-        if (type.arraySize)
-            variable->getType().setArraySize(type.arraySize);
+        variable->getType().setArraySizes(type.arraySizes);
     } 
 
     if (voidErrorCheck(line, identifier, type))
@@ -1094,10 +1095,15 @@ bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPu
         error(line, " cannot initialize this type of qualifier ", variable->getType().getStorageQualifierString(), "");
         return true;
     }
+
+    // Fix arrayness if variable is unsized, getting size for initializer    
+    if (initializer->getType().isArray() && initializer->getType().getArraySize() > 0 && 
+                            type.isArray() &&                   type.getArraySize() == 0)
+        type.changeArraySize(initializer->getType().getArraySize());
+
     //
     // test for and propagate constant
     //
-
     if (qualifier == EvqConst) {
         if (qualifier != initializer->getType().getQualifier().storage) {
             error(line, " assigning non-constant to", "=", "'%s'", variable->getType().getCompleteString().c_str());
@@ -1471,8 +1477,8 @@ TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, TS
     TType arrayElementType = node->getType();
     arrayElementType.dereference();
 
-    if (index >= node->getType().getArraySize()) {
-        error(line, "", "[", "array index out of range '%d'", index);
+    if (index >= node->getType().getArraySize() || index < 0) {
+        error(line, "", "[", "array index '%d' out of range", index);
         recover();
         index = 0;
     }
index 6af1c95..d3ea23c 100644 (file)
@@ -125,7 +125,7 @@ struct TParseContext {
     bool structQualifierErrorCheck(int line, const TPublicType& pType);
     void setDefaultPrecision(int line, TBasicType, TPrecisionQualifier);
     bool parameterSamplerErrorCheck(int line, TStorageQualifier qualifier, const TType& type);
-    bool containsSampler(TType& type);
+    bool containsSampler(const TType& type);
     bool nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type);
     bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type);
     bool paramErrorCheck(int line, TStorageQualifier qualifier, TType* type);
@@ -154,7 +154,7 @@ int PaParseStrings(char* argv[], int strLen[], int argc, TParseContext&);
 void PaReservedWord();
 int PaIdentOrType(TString& id, TParseContext&, TSymbol*&);
 int PaParseComment(int &lineno, TParseContext&);
-void setInitialState();
+void ResetFlex();
 
 typedef TParseContext* TParseContextPointer;
 extern TParseContextPointer& GetGlobalParseContext();
index 4c1d909..dce9887 100644 (file)
@@ -194,13 +194,11 @@ bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, EShLanguage language
 
     GlobalParseContext = &parseContext;
     
-    setInitialState();
-
     assert(symbolTable->isEmpty() || symbolTable->atSharedBuiltInLevel());
        
     //
     // Parse the built-ins.  This should only happen once per
-    // language symbol table.
+    // language symbol table when no 'resources' are passed in.
     //
     // Push the symbol table to give it an initial scope.  This
     // push should not have a corresponding pop, so that built-ins
@@ -208,6 +206,7 @@ bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, EShLanguage language
     //
 
     symbolTable->push();
+
     
     //Initialize the Preprocessor
     int ret = InitPreprocessor();
@@ -215,6 +214,8 @@ bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, EShLanguage language
         infoSink.info.message(EPrefixInternalError,  "Unable to intialize the Preprocessor");
         return false;
     }
+
+    ResetFlex();
     
     for (TBuiltInStrings::iterator i  = BuiltInStrings[parseContext.language].begin();
                                    i != BuiltInStrings[parseContext.language].end();    ++i) {
@@ -229,15 +230,13 @@ bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, EShLanguage language
             return false;
         }
     }
+    FinalizePreprocessor();
 
        if (resources) {
                IdentifyBuiltIns(parseContext.language, *symbolTable, *resources);
-       } else {                                                                           
+       } else {
                IdentifyBuiltIns(parseContext.language, *symbolTable);
        }
-
-    FinalizePreprocessor();
-
     return true;
 }
 
@@ -279,6 +278,8 @@ int ShCompile(
     TIntermediate intermediate(compiler->infoSink);
     TSymbolTable symbolTable(SymbolTables[compiler->getLanguage()]);
     
+    // Add built-in symbols that are potentially context dependent;
+    // they get popped again further down.
     GenerateBuiltInSymbolTable(resources, compiler->infoSink, &symbolTable, compiler->getLanguage());
 
     TParseContext parseContext(symbolTable, intermediate, compiler->getLanguage(), compiler->infoSink, defaultVersion);
@@ -286,9 +287,9 @@ int ShCompile(
 
     GlobalParseContext = &parseContext;
     
-    setInitialState();
+    ResetFlex();
+    InitPreprocessor();
 
-    InitPreprocessor();    
     //
     // Parse the application's shaders.  All the following symbol table
     // work will be throw-away, so push a new allocation scope that can
index 27afc1e..15cc52b 100644 (file)
@@ -87,10 +87,10 @@ void TType::buildMangledName(TString& mangledName)
         mangledName += static_cast<char>('0' + getMatrixRows());
     }
 
-    if (isArray()) {
+    if (arraySizes) {
                const int maxSize = 10;
         char buf[maxSize];
-        sprintf_s(buf, maxSize, "%d", arraySize);
+        sprintf_s(buf, maxSize, "%d", arraySizes->front());
         mangledName += '[';
         mangledName += buf;
         mangledName += ']';
index 52488cb..49d4f58 100644 (file)
@@ -861,7 +861,7 @@ void updateExtensionBehavior(const char* extName, const char* behavior)
 \r
 }  // extern "C"\r
 \r
-void setInitialState()\r
+void ResetFlex()\r
 {\r
     yy_start = 1;\r
 }\r
index 8be6fbd..dae3e3f 100644 (file)
@@ -101,7 +101,7 @@ Jutta Degener, 1995
             TParameter param;\r
             TTypeLine typeLine;\r
             TTypeList* typeList;\r
-            TVector<int>* intVector;\r
+            TArraySizes arraySizes;\r
         };\r
     } interm;\r
 }\r
@@ -321,7 +321,8 @@ postfix_expression
                                 if (parseContext.arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), 0, false, $2.line))\r
                                     parseContext.recover();\r
                             }\r
-                        } else if ( $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= $1->getType().getArraySize()) {\r
+                        } else if ( $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= $1->getType().getArraySize() ||\r
+                                    $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() < 0) {\r
                             parseContext.error($2.line, "", "[", "array index out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst());\r
                             parseContext.recover();\r
                         }\r
@@ -345,8 +346,8 @@ postfix_expression
             TType newType = $1->getType();\r
             newType.dereference();\r
             $$->setType(newType);\r
-            //?? why didn't the code above get the type right?\r
-            //?? write a deference test\r
+            //?? why wouldn't the code above get the type right?\r
+            //?? write a dereference test\r
         }\r
     }\r
     | function_call {\r
@@ -444,8 +445,7 @@ postfix_expression
                 }\r
             }\r
         } else {\r
-            //?? fix message\r
-            parseContext.error($2.line, " field selection requires structure, vector, or matrix on left hand side", $3.string->c_str(), "");\r
+            parseContext.error($2.line, " dot operator requires structure, array, vector, or matrix on left hand side", $3.string->c_str(), "");\r
             parseContext.recover();\r
             $$ = $1;\r
         }\r
@@ -489,13 +489,16 @@ function_call
         TOperator op = fnCall->getBuiltInOp();\r
         if (op == EOpArrayLength) {\r
             // TODO: check for no arguments to .length()\r
-            if ($1.intermNode->getAsTyped() == 0 || $1.intermNode->getAsTyped()->getType().getArraySize() == 0) {\r
+            int length;\r
+            if ($1.intermNode->getAsTyped() == 0 || ! $1.intermNode->getAsTyped()->getType().isArray() || $1.intermNode->getAsTyped()->getType().getArraySize() == 0) {\r
                 parseContext.error($1.line, "", fnCall->getName().c_str(), "array must be declared with a size before using this method");\r
                 parseContext.recover();\r
-            }\r
+                length = 1;\r
+            } else\r
+                length = $1.intermNode->getAsTyped()->getType().getArraySize();\r
 \r
             constUnion *unionArray = new constUnion[1];\r
-            unionArray->setIConst($1.intermNode->getAsTyped()->getType().getArraySize());\r
+            unionArray->setIConst(length);\r
             $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $1.line);\r
         } else if (op != EOpNull) {\r
             //\r
@@ -647,8 +650,9 @@ function_identifier
         $$.function = 0;\r
         $$.intermNode = 0;\r
 \r
-        if ($1.array) {\r
-            parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "array");\r
+        if ($1.arraySizes) {\r
+            parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed constructor");\r
+            parseContext.profileRequires($1.line, EEsProfile, 300, "GL_3DL_array_objects", "arrayed constructor");\r
         }\r
 \r
         $1.qualifier.precision = EpqNone;\r
@@ -1284,6 +1288,10 @@ function_header
 parameter_declarator\r
     // Type + name\r
     : type_specifier IDENTIFIER {\r
+        if ($1.arraySizes) {\r
+            parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type");\r
+            parseContext.profileRequires($1.line, EEsProfile, 300, 0, "arrayed type");\r
+        }\r
         if ($1.type == EbtVoid) {\r
             parseContext.error($2.line, "illegal use of type 'void'", $2.string->c_str(), "");\r
             parseContext.recover();\r
@@ -1296,13 +1304,18 @@ parameter_declarator
         $$.param = param;\r
     }\r
     | type_specifier IDENTIFIER array_specifier {\r
-        if (parseContext.arraySizeRequiredErrorCheck($3.line, $3.intVector->front()))\r
+        if ($1.arraySizes) {\r
+            parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type");\r
+            parseContext.profileRequires($1.line, EEsProfile, 300, 0, "arrayed type");\r
+        }\r
+\r
+        if (parseContext.arraySizeRequiredErrorCheck($3.line, $3.arraySizes->front()))\r
             parseContext.recover();\r
 \r
         if (parseContext.reservedErrorCheck($2.line, *$2.string))\r
             parseContext.recover();\r
 \r
-        $1.setArray(true, $3.intVector->front());\r
+        $1.arraySizes = $3.arraySizes;\r
 \r
         TParameter param = { $2.string, new TType($1)};\r
         $$.line = $2.line;\r
@@ -1389,7 +1402,7 @@ init_declarator_list
         if (parseContext.arrayQualifierErrorCheck($4.line, $1.type))\r
             parseContext.recover();\r
         else {\r
-            $1.type.setArray(true, $4.intVector->front());\r
+            $1.type.arraySizes = $4.arraySizes;\r
             TVariable* variable;\r
             if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable))\r
                 parseContext.recover();\r
@@ -1405,7 +1418,7 @@ init_declarator_list
         if (parseContext.arrayQualifierErrorCheck($4.line, $1.type))\r
             parseContext.recover();\r
         else {\r
-            $1.type.setArray(true, $4.intVector->front());\r
+            $1.type.arraySizes = $4.arraySizes;\r
             if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable))\r
                 parseContext.recover();\r
         }\r
@@ -1490,7 +1503,7 @@ single_declaration
         if (parseContext.arrayQualifierErrorCheck($3.line, $1))\r
             parseContext.recover();\r
         else {\r
-            $1.setArray(true, $3.intVector->front());\r
+            $1.arraySizes = $3.arraySizes;\r
             TVariable* variable;\r
             if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable))\r
                 parseContext.recover();\r
@@ -1508,7 +1521,7 @@ single_declaration
         if (parseContext.arrayQualifierErrorCheck($3.line, $1))\r
             parseContext.recover();\r
         else {\r
-            $1.setArray(true, $3.intVector->front());\r
+            $1.arraySizes = $3.arraySizes;\r
             if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable))\r
                 parseContext.recover();\r
         }\r
@@ -1556,17 +1569,20 @@ fully_specified_type
     : type_specifier {\r
         $$ = $1;\r
 \r
-        if ($1.array) {\r
-            parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "array");\r
+        if ($1.arraySizes) {\r
+            parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type");\r
+            parseContext.profileRequires($1.line, EEsProfile, 300, 0, "arrayed type");\r
         }\r
     }\r
     | type_qualifier type_specifier  {\r
-        if ($2.array)\r
-            parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "array");\r
+        if ($2.arraySizes) {\r
+            parseContext.profileRequires($2.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type");\r
+            parseContext.profileRequires($2.line, EEsProfile, 300, 0, "arrayed type");\r
+        }\r
 \r
-        if ($2.array && parseContext.arrayQualifierErrorCheck($2.line, $1)) {\r
+        if ($2.arraySizes && parseContext.arrayQualifierErrorCheck($2.line, $1)) {\r
             parseContext.recover();\r
-            $2.setArray(false);\r
+            $2.arraySizes = 0;\r
         }\r
 \r
         if ($1.qualifier.storage == EvqAttribute &&\r
@@ -1833,28 +1849,28 @@ type_specifier
     | type_specifier_nonarray array_specifier {\r
         $$ = $1;\r
         $$.qualifier.precision = parseContext.defaultPrecision[$$.type];\r
-        $$.setArray(true, $2.intVector->front());\r
+        $$.arraySizes = $2.arraySizes;\r
     }\r
     ;\r
 \r
 array_specifier\r
     : LEFT_BRACKET RIGHT_BRACKET {\r
         $$.line = $1.line;\r
-        $$.intVector = new TVector<int>;\r
-        $$.intVector->push_back(0);\r
+        $$.arraySizes = NewPoolTArraySizes();\r
+        $$.arraySizes->push_back(0);\r
     }\r
     | LEFT_BRACKET constant_expression RIGHT_BRACKET {\r
         $$.line = $1.line;\r
-        $$.intVector = new TVector<int>;\r
+        $$.arraySizes = NewPoolTArraySizes();\r
 \r
         int size;\r
         if (parseContext.arraySizeErrorCheck($2->getLine(), $2, size))\r
             parseContext.recover();\r
-        $$.intVector->push_back(size);\r
+        $$.arraySizes->push_back(size);\r
     }\r
     | array_specifier LEFT_BRACKET RIGHT_BRACKET {\r
         $$ = $1;\r
-        $$.intVector->push_back(0);\r
+        $$.arraySizes->push_back(0);\r
     }\r
     | array_specifier LEFT_BRACKET constant_expression RIGHT_BRACKET {\r
         $$ = $1;\r
@@ -1862,7 +1878,7 @@ array_specifier
         int size;\r
         if (parseContext.arraySizeErrorCheck($3->getLine(), $3, size))\r
             parseContext.recover();\r
-        $$.intVector->push_back(size);\r
+        $$.arraySizes->push_back(size);\r
     }\r
     ;\r
 \r
@@ -2443,7 +2459,7 @@ type_specifier_nonarray
         // This is for user defined type names.  The lexical phase looked up the\r
         // type.\r
         //\r
-        TType& structure = static_cast<TVariable*>($1.symbol)->getType();\r
+        const TType& structure = static_cast<const TVariable*>($1.symbol)->getType();\r
         $$.init($1.line, parseContext.symbolTable.atGlobalLevel());\r
         $$.type = EbtStruct;\r
         $$.userDef = &structure;\r
@@ -2511,6 +2527,11 @@ struct_declaration_list
 \r
 struct_declaration\r
     : type_specifier struct_declarator_list SEMICOLON {\r
+        if ($1.arraySizes) {\r
+            parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type");\r
+            parseContext.profileRequires($1.line, EEsProfile, 300, 0, "arrayed type");\r
+        }\r
+\r
         $$ = $2;\r
 \r
         if (parseContext.voidErrorCheck($1.line, (*$2)[0].type->getFieldName(), $1)) {\r
@@ -2522,13 +2543,18 @@ struct_declaration
             //\r
             (*$$)[i].type->setElementType($1.type, $1.vectorSize, $1.matrixCols, $1.matrixRows, $1.userDef);\r
 \r
-            if ($1.array)\r
-                (*$$)[i].type->setArraySize($1.arraySize);\r
+            if ($1.arraySizes)\r
+                (*$$)[i].type->setArraySizes($1.arraySizes);\r
             if ($1.userDef)\r
                 (*$$)[i].type->setTypeName($1.userDef->getTypeName());\r
         }\r
     }\r
     | type_qualifier type_specifier struct_declarator_list SEMICOLON {\r
+        if ($2.arraySizes) {\r
+            parseContext.profileRequires($2.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type");\r
+            parseContext.profileRequires($2.line, EEsProfile, 300, 0, "arrayed type");\r
+        }\r
+\r
         $$ = $3;\r
 \r
         if (parseContext.voidErrorCheck($2.line, (*$3)[0].type->getFieldName(), $2)) {\r
@@ -2540,8 +2566,8 @@ struct_declaration
             //\r
             (*$$)[i].type->setElementType($2.type, $2.vectorSize, $2.matrixCols, $2.matrixRows, $2.userDef);\r
 \r
-            if ($2.array)\r
-                (*$$)[i].type->setArraySize($2.arraySize);\r
+            if ($2.arraySizes)\r
+                (*$$)[i].type->setArraySizes($2.arraySizes);\r
             if ($2.userDef)\r
                 (*$$)[i].type->setTypeName($2.userDef->getTypeName());\r
         }\r
@@ -2568,7 +2594,7 @@ struct_declarator
         $$.type = new TType(EbtVoid);\r
         $$.line = $1.line;\r
         $$.type->setFieldName(*$1.string);\r
-        $$.type->setArraySize($2.intVector->front());\r
+        $$.type->setArraySizes($2.arraySizes);\r
     }\r
     ;\r
 \r
index 16a8d5f..8520642 100644 (file)
@@ -64,8 +64,12 @@ TString TType::getCompleteString() const
 
     if (qualifier.storage != EvqTemporary && qualifier.storage != EvqGlobal)
         p += sprintf_s(p, end - p, "%s ", getStorageQualifierString());
-    if (array)
-        p += sprintf_s(p, end - p, "array of ");
+    if (arraySizes) {
+        if (arraySizes->front() == 0)
+            p += sprintf_s(p, end - p, "unsized array of ");
+        else
+            p += sprintf_s(p, end - p, "%d-element array of ", arraySizes->front());
+    }
     if (qualifier.precision != EpqNone)
         p += sprintf_s(p, end - p, "%s ", getPrecisionQualifierString());
     if (matrixCols > 0)