diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp index 921fddd84d991c70b20965aefc3013e7fa1daac3..38fe21390dd5050279c3d5e292997413fd064672 100644 --- a/StandAlone/StandAlone.cpp +++ b/StandAlone/StandAlone.cpp @@ -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 index 0000000000000000000000000000000000000000..090d353da495bcbb3a944f5d4da5c9a0f2064fed --- /dev/null +++ b/Test/array.frag @@ -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 index 0000000000000000000000000000000000000000..87c125b7d31ab961d7a1f57f267838c25cd3ae98 --- /dev/null +++ b/Test/array100.frag @@ -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); +} diff --git a/Test/testlist b/Test/testlist index 6e8805858d6801c858725f2e1eec8ddbbaba4d93..afe4f9b52e167b8357bc5d8c9022e59f74724eb3 100644 --- a/Test/testlist +++ b/Test/testlist @@ -17,3 +17,5 @@ cppIndent.vert cppNest.vert cppComplexExpr.vert pointCoord.frag +array.frag +array100.frag \ No newline at end of file diff --git a/glslang/Include/BaseTypes.h b/glslang/Include/BaseTypes.h index ef3f910171500ef6136f395f454568e25cfea77d..c22277cf6df2ff94f930c0d9c8c0d0da0d684a4d 100644 --- a/glslang/Include/BaseTypes.h +++ b/glslang/Include/BaseTypes.h @@ -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"; } } diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index ab665454b9e19ad911a026c3d9cbd2ba7ec9d8c1..b6eaac9d235ab804c99be76479401dc5171daa98 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -56,6 +56,24 @@ inline TTypeList* NewPoolTTypeList() return new(memory) TTypeList; } +// +// 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 @@ -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; diff --git a/glslang/MachineIndependent/Initialize.cpp b/glslang/MachineIndependent/Initialize.cpp index a02f0a30c1e73f7b180420d1968b1d2516bcabc5..ad428a7420d70e1916e77150547214cbee6b1545 100644 --- a/glslang/MachineIndependent/Initialize.cpp +++ b/glslang/MachineIndependent/Initialize.cpp @@ -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; diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 189d197268acf13ed60ef76065a492514b257ad9..8c1ced7e04f5d65c93b6c123a157cf0f11214526 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -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; } diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index 6af1c95bfc5553f5cc1085261281f28703ba1073..d3ea23cd17739800d8bc2c96b1bec82e5bca9534 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -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(); diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index 4c1d909f59054f6084a9fdecf116b35ee9fbe471..dce9887476bd9b8105e7db8a52cfc2097bdfbc61 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -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 diff --git a/glslang/MachineIndependent/SymbolTable.cpp b/glslang/MachineIndependent/SymbolTable.cpp index 27afc1e5419d25df71c0579edd9881c7e0c79107..15cc52bba4b3673cd29b25725a6f3da0ddce7d92 100644 --- a/glslang/MachineIndependent/SymbolTable.cpp +++ b/glslang/MachineIndependent/SymbolTable.cpp @@ -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 += ']'; diff --git a/glslang/MachineIndependent/glslang.l b/glslang/MachineIndependent/glslang.l index 52488cbfcc859e19148cc7fe12e40e7eb1fc2f01..49d4f58862634c7a23b6dabb04127083811d4e89 100644 --- a/glslang/MachineIndependent/glslang.l +++ b/glslang/MachineIndependent/glslang.l @@ -861,7 +861,7 @@ void updateExtensionBehavior(const char* extName, const char* behavior) } // extern "C" -void setInitialState() +void ResetFlex() { yy_start = 1; } diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index 8be6fbdc924169f44426f03d2cc5758bbe753d9e..dae3e3f3b9d87c9de17802f4caed322d8b3c5756 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -101,7 +101,7 @@ Jutta Degener, 1995 TParameter param; TTypeLine typeLine; TTypeList* typeList; - TVector<int>* intVector; + TArraySizes arraySizes; }; } interm; } @@ -321,7 +321,8 @@ postfix_expression if (parseContext.arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), 0, false, $2.line)) parseContext.recover(); } - } else if ( $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= $1->getType().getArraySize()) { + } else if ( $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= $1->getType().getArraySize() || + $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() < 0) { parseContext.error($2.line, "", "[", "array index out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst()); parseContext.recover(); } @@ -345,8 +346,8 @@ postfix_expression TType newType = $1->getType(); newType.dereference(); $$->setType(newType); - //?? why didn't the code above get the type right? - //?? write a deference test + //?? why wouldn't the code above get the type right? + //?? write a dereference test } } | function_call { @@ -444,8 +445,7 @@ postfix_expression } } } else { - //?? fix message - parseContext.error($2.line, " field selection requires structure, vector, or matrix on left hand side", $3.string->c_str(), ""); + parseContext.error($2.line, " dot operator requires structure, array, vector, or matrix on left hand side", $3.string->c_str(), ""); parseContext.recover(); $$ = $1; } @@ -489,13 +489,16 @@ function_call TOperator op = fnCall->getBuiltInOp(); if (op == EOpArrayLength) { // TODO: check for no arguments to .length() - if ($1.intermNode->getAsTyped() == 0 || $1.intermNode->getAsTyped()->getType().getArraySize() == 0) { + int length; + if ($1.intermNode->getAsTyped() == 0 || ! $1.intermNode->getAsTyped()->getType().isArray() || $1.intermNode->getAsTyped()->getType().getArraySize() == 0) { parseContext.error($1.line, "", fnCall->getName().c_str(), "array must be declared with a size before using this method"); parseContext.recover(); - } + length = 1; + } else + length = $1.intermNode->getAsTyped()->getType().getArraySize(); constUnion *unionArray = new constUnion[1]; - unionArray->setIConst($1.intermNode->getAsTyped()->getType().getArraySize()); + unionArray->setIConst(length); $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $1.line); } else if (op != EOpNull) { // @@ -647,8 +650,9 @@ function_identifier $$.function = 0; $$.intermNode = 0; - if ($1.array) { - parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "array"); + if ($1.arraySizes) { + parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed constructor"); + parseContext.profileRequires($1.line, EEsProfile, 300, "GL_3DL_array_objects", "arrayed constructor"); } $1.qualifier.precision = EpqNone; @@ -1284,6 +1288,10 @@ function_header parameter_declarator // Type + name : type_specifier IDENTIFIER { + if ($1.arraySizes) { + parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type"); + parseContext.profileRequires($1.line, EEsProfile, 300, 0, "arrayed type"); + } if ($1.type == EbtVoid) { parseContext.error($2.line, "illegal use of type 'void'", $2.string->c_str(), ""); parseContext.recover(); @@ -1296,13 +1304,18 @@ parameter_declarator $$.param = param; } | type_specifier IDENTIFIER array_specifier { - if (parseContext.arraySizeRequiredErrorCheck($3.line, $3.intVector->front())) + if ($1.arraySizes) { + parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type"); + parseContext.profileRequires($1.line, EEsProfile, 300, 0, "arrayed type"); + } + + if (parseContext.arraySizeRequiredErrorCheck($3.line, $3.arraySizes->front())) parseContext.recover(); if (parseContext.reservedErrorCheck($2.line, *$2.string)) parseContext.recover(); - $1.setArray(true, $3.intVector->front()); + $1.arraySizes = $3.arraySizes; TParameter param = { $2.string, new TType($1)}; $$.line = $2.line; @@ -1389,7 +1402,7 @@ init_declarator_list if (parseContext.arrayQualifierErrorCheck($4.line, $1.type)) parseContext.recover(); else { - $1.type.setArray(true, $4.intVector->front()); + $1.type.arraySizes = $4.arraySizes; TVariable* variable; if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable)) parseContext.recover(); @@ -1405,7 +1418,7 @@ init_declarator_list if (parseContext.arrayQualifierErrorCheck($4.line, $1.type)) parseContext.recover(); else { - $1.type.setArray(true, $4.intVector->front()); + $1.type.arraySizes = $4.arraySizes; if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable)) parseContext.recover(); } @@ -1490,7 +1503,7 @@ single_declaration if (parseContext.arrayQualifierErrorCheck($3.line, $1)) parseContext.recover(); else { - $1.setArray(true, $3.intVector->front()); + $1.arraySizes = $3.arraySizes; TVariable* variable; if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable)) parseContext.recover(); @@ -1508,7 +1521,7 @@ single_declaration if (parseContext.arrayQualifierErrorCheck($3.line, $1)) parseContext.recover(); else { - $1.setArray(true, $3.intVector->front()); + $1.arraySizes = $3.arraySizes; if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable)) parseContext.recover(); } @@ -1556,17 +1569,20 @@ fully_specified_type : type_specifier { $$ = $1; - if ($1.array) { - parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "array"); + if ($1.arraySizes) { + parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type"); + parseContext.profileRequires($1.line, EEsProfile, 300, 0, "arrayed type"); } } | type_qualifier type_specifier { - if ($2.array) - parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "array"); + if ($2.arraySizes) { + parseContext.profileRequires($2.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type"); + parseContext.profileRequires($2.line, EEsProfile, 300, 0, "arrayed type"); + } - if ($2.array && parseContext.arrayQualifierErrorCheck($2.line, $1)) { + if ($2.arraySizes && parseContext.arrayQualifierErrorCheck($2.line, $1)) { parseContext.recover(); - $2.setArray(false); + $2.arraySizes = 0; } if ($1.qualifier.storage == EvqAttribute && @@ -1833,28 +1849,28 @@ type_specifier | type_specifier_nonarray array_specifier { $$ = $1; $$.qualifier.precision = parseContext.defaultPrecision[$$.type]; - $$.setArray(true, $2.intVector->front()); + $$.arraySizes = $2.arraySizes; } ; array_specifier : LEFT_BRACKET RIGHT_BRACKET { $$.line = $1.line; - $$.intVector = new TVector<int>; - $$.intVector->push_back(0); + $$.arraySizes = NewPoolTArraySizes(); + $$.arraySizes->push_back(0); } | LEFT_BRACKET constant_expression RIGHT_BRACKET { $$.line = $1.line; - $$.intVector = new TVector<int>; + $$.arraySizes = NewPoolTArraySizes(); int size; if (parseContext.arraySizeErrorCheck($2->getLine(), $2, size)) parseContext.recover(); - $$.intVector->push_back(size); + $$.arraySizes->push_back(size); } | array_specifier LEFT_BRACKET RIGHT_BRACKET { $$ = $1; - $$.intVector->push_back(0); + $$.arraySizes->push_back(0); } | array_specifier LEFT_BRACKET constant_expression RIGHT_BRACKET { $$ = $1; @@ -1862,7 +1878,7 @@ array_specifier int size; if (parseContext.arraySizeErrorCheck($3->getLine(), $3, size)) parseContext.recover(); - $$.intVector->push_back(size); + $$.arraySizes->push_back(size); } ; @@ -2443,7 +2459,7 @@ type_specifier_nonarray // This is for user defined type names. The lexical phase looked up the // type. // - TType& structure = static_cast<TVariable*>($1.symbol)->getType(); + const TType& structure = static_cast<const TVariable*>($1.symbol)->getType(); $$.init($1.line, parseContext.symbolTable.atGlobalLevel()); $$.type = EbtStruct; $$.userDef = &structure; @@ -2511,6 +2527,11 @@ struct_declaration_list struct_declaration : type_specifier struct_declarator_list SEMICOLON { + if ($1.arraySizes) { + parseContext.profileRequires($1.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type"); + parseContext.profileRequires($1.line, EEsProfile, 300, 0, "arrayed type"); + } + $$ = $2; if (parseContext.voidErrorCheck($1.line, (*$2)[0].type->getFieldName(), $1)) { @@ -2522,13 +2543,18 @@ struct_declaration // (*$$)[i].type->setElementType($1.type, $1.vectorSize, $1.matrixCols, $1.matrixRows, $1.userDef); - if ($1.array) - (*$$)[i].type->setArraySize($1.arraySize); + if ($1.arraySizes) + (*$$)[i].type->setArraySizes($1.arraySizes); if ($1.userDef) (*$$)[i].type->setTypeName($1.userDef->getTypeName()); } } | type_qualifier type_specifier struct_declarator_list SEMICOLON { + if ($2.arraySizes) { + parseContext.profileRequires($2.line, ENoProfile, 120, "GL_3DL_array_objects", "arrayed type"); + parseContext.profileRequires($2.line, EEsProfile, 300, 0, "arrayed type"); + } + $$ = $3; if (parseContext.voidErrorCheck($2.line, (*$3)[0].type->getFieldName(), $2)) { @@ -2540,8 +2566,8 @@ struct_declaration // (*$$)[i].type->setElementType($2.type, $2.vectorSize, $2.matrixCols, $2.matrixRows, $2.userDef); - if ($2.array) - (*$$)[i].type->setArraySize($2.arraySize); + if ($2.arraySizes) + (*$$)[i].type->setArraySizes($2.arraySizes); if ($2.userDef) (*$$)[i].type->setTypeName($2.userDef->getTypeName()); } @@ -2568,7 +2594,7 @@ struct_declarator $$.type = new TType(EbtVoid); $$.line = $1.line; $$.type->setFieldName(*$1.string); - $$.type->setArraySize($2.intVector->front()); + $$.type->setArraySizes($2.arraySizes); } ; diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp index 16a8d5fab67f85842eb550c4d5cd6e6ffb462856..8520642d6f5cbcfed1ff17af5332124ca247b96f 100644 --- a/glslang/MachineIndependent/intermOut.cpp +++ b/glslang/MachineIndependent/intermOut.cpp @@ -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)