{
return v1(); // ERROR, no expression allowed, even though void
}
+
+void atest()
+{
+ vec4 v = gl_TexCoord[1];
+ v += gl_TexCoord[3];
+}
+
+varying vec4 gl_TexCoord[6]; // okay, assigning a size
+varying vec4 gl_TexCoord[5]; // ERROR, changing size
ERROR: 0:97: 'out' : overloaded functions must have the same parameter qualifiers \r
ERROR: 0:99: 'return' : function return is not matching type: \r
ERROR: 0:115: 'return' : void function cannot return a value \r
-ERROR: 29 compilation errors. No code generated.\r
+ERROR: 0:125: 'gl_TexCoord' : redeclaration of array with size \r
+ERROR: 30 compilation errors. No code generated.\r
\r
ERROR: node is still EOpNull!\r
0:21 Function Definition: main( (void)\r
0:115 Sequence\r
0:115 Branch: Return with expression\r
0:115 Function Call: v1( (void)\r
+0:118 Function Definition: atest( (void)\r
+0:118 Function Parameters: \r
+0:120 Sequence\r
+0:120 Sequence\r
+0:120 move second child to first child (4-component vector of float)\r
+0:120 'v' (4-component vector of float)\r
+0:120 direct index (smooth in 4-component vector of float)\r
+0:120 'gl_TexCoord' (smooth in unsized array of 4-component vector of float)\r
+0:120 1 (const int)\r
+0:121 add second child into first child (4-component vector of float)\r
+0:121 'v' (4-component vector of float)\r
+0:121 direct index (smooth in 4-component vector of float)\r
+0:121 'gl_TexCoord' (smooth in unsized array of 4-component vector of float)\r
+0:121 3 (const int)\r
0:? Linker Objects\r
0:? 'i' (smooth in 4-component vector of float)\r
0:? 'o' (out 4-component vector of float)\r
0:? 'rep2' (centroid smooth sample out highp 4-component vector of float)\r
0:? 'rep3' (in highp 4-component vector of float)\r
0:? 's' (smooth out structure)\r
-0:? 'ubInst' (layout(shared ) uniform 1-element array of block)\r
+0:? 'ubInst' (layout(shared ) uniform unsized array of block)\r
0:? 'gl_VertexID' (gl_VertexId highp int)\r
0:? 'gl_InstanceID' (gl_InstanceId highp int)\r
\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:25: 'assign' : cannot convert from '4-element array of mediump float' to '5-element array of mediump float'\r
-ERROR: 0:26: 'assign' : cannot convert from '4-element array of mediump float' to '1-element array of mediump float'\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:35: '[' : array index out of range '5'\r
0:24 Function Call: foo(f1[5]; (4-element array of mediump float)\r
0:24 'g5' (5-element array of mediump float)\r
0:25 'g5' (5-element array of mediump float)\r
-0:26 'gu' (1-element array of mediump float)\r
+0:26 'gu' (unsized array of mediump float)\r
0:28 0.000000\r
0:29 Function Call: bar(f1[5]; (void)\r
0:29 'g5' (5-element array of mediump float)\r
0:31 true case\r
0:32 move second child to first child (mediump float)\r
0:32 direct index (mediump float)\r
-0:32 'gu' (1-element array of mediump float)\r
+0:32 'gu' (unsized array of mediump float)\r
0:32 0 (const int)\r
0:32 2.000000\r
0:35 move second child to first child (mediump float)\r
// 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;
+struct TArraySizes {
+ TArraySizes() : maxArraySize(0) { }
+ int getSize() { return sizes.front(); } // TArraySizes only exists if there is at least one dimension
+ void setSize(int s) { sizes.push_back(s); }
+ bool isArrayOfArrays() { return sizes.size() > 1; }
+protected:
+ TVector<int> sizes;
+ friend class TType;
+ int maxArraySize; // for tracking maximum referenced index, before an explicit size is given
+};
-inline TArraySizes NewPoolTArraySizes()
+inline TArraySizes* NewPoolTArraySizes()
{
- void* memory = GetThreadPoolAllocator().allocate(sizeof(TVector<int>));
- return new(memory) TVector<int>;
+ void* memory = GetThreadPoolAllocator().allocate(sizeof(TArraySizes));
+ return new(memory) TArraySizes;
}
//
int vectorSize : 4;
int matrixCols : 4;
int matrixRows : 4;
- TArraySizes arraySizes;
+ TArraySizes* arraySizes;
const TType* userDef;
TSourceLoc loc;
typedef std::map<TTypeList*, TTypeList*> TStructureMap;
typedef std::map<TTypeList*, TTypeList*>::const_iterator TStructureMapIterator;
+
//
// Base class for things that have a type.
//
class TType {
public:
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
- explicit TType(TBasicType t, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0) :
+ explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0) :
basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0),
- structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0),
- fieldName(0), typeName(0)
+ structure(0), structureSize(0), fieldName(0), typeName(0)
{
sampler.clear();
qualifier.clear();
}
TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0) :
basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0),
- structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0),
- fieldName(0), typeName(0)
+ structure(0), structureSize(0), fieldName(0), typeName(0)
{
sampler.clear();
qualifier.clear();
}
explicit TType(const TPublicType &p) :
basicType(p.basicType), vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), arraySizes(p.arraySizes),
- structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), typeName(0)
+ structure(0), structureSize(0), fieldName(0), typeName(0)
{
if (basicType == EbtSampler)
sampler = p.sampler;
}
TType(TTypeList* userDef, const TString& n, TStorageQualifier blockQualifier = EvqGlobal) :
basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), arraySizes(0),
- structure(userDef), maxArraySize(0), arrayInformationType(0), fieldName(0)
+ structure(userDef), fieldName(0)
{
sampler.clear();
qualifier.clear();
}
typeName = NewPoolTString(n.c_str());
}
- TType() {}
virtual ~TType() {}
-
- // "dumb" copy, using built-in operator=(), not for use across pool pops.
- // It will also cause multiple copies of TType to point to the same information.
- // This only works if that information (like a structure's list of types) does not
- // change.
- explicit TType(const TType& type) { *this = type; }
-
- void copyType(const TType& copyOf, const TStructureMap& remapper)
- {
+
+ // Not for use across pool pops; it will cause multiple instances of TType to point to the same information.
+ // This only works if that information (like a structure's list of types) does not change and
+ // the instances are sharing the same pool.
+ void shallowCopy(const TType& copyOf)
+ {
basicType = copyOf.basicType;
sampler = copyOf.sampler;
qualifier = copyOf.qualifier;
vectorSize = copyOf.vectorSize;
matrixCols = copyOf.matrixCols;
matrixRows = copyOf.matrixRows;
+ arraySizes = copyOf.arraySizes;
+ structure = copyOf.structure;
+ structureSize = copyOf.structureSize;
+ fieldName = copyOf.fieldName;
+ typeName = copyOf.typeName;
+ }
- if (copyOf.arraySizes) {
+ void deepCopy(const TType& copyOf, const TStructureMap& remapper)
+ {
+ shallowCopy(copyOf);
+
+ if (arraySizes) {
arraySizes = NewPoolTArraySizes();
*arraySizes = *copyOf.arraySizes;
- } else
- arraySizes = 0;
+ }
- TStructureMapIterator iter;
- if (copyOf.structure) {
+ if (structure) {
+ TStructureMapIterator iter;
if ((iter = remapper.find(structure)) == remapper.end()) {
// create the new structure here
structure = NewPoolTTypeList();
} else {
structure = iter->second;
}
- } else
- structure = 0;
+ }
- fieldName = 0;
- if (copyOf.fieldName)
+ if (fieldName)
fieldName = NewPoolTString(copyOf.fieldName->c_str());
- typeName = 0;
- if (copyOf.typeName)
+ if (typeName)
typeName = NewPoolTString(copyOf.typeName->c_str());
-
- structureSize = copyOf.structureSize;
- maxArraySize = copyOf.maxArraySize;
- assert(copyOf.arrayInformationType == 0);
- arrayInformationType = 0; // arrayInformationType should not be set for builtIn symbol table level
}
// Merge type from parent, where a parentType is at the beginning of a declaration,
TType* clone(const TStructureMap& remapper)
{
TType *newType = new TType();
- newType->copyType(*this, remapper);
+ newType->deepCopy(*this, remapper);
return newType;
}
virtual void dereference()
{
- if (arraySizes) {
+ if (arraySizes)
arraySizes = 0;
- maxArraySize = 0;
- } else if (matrixCols > 0) {
+ else if (matrixCols > 0) {
vectorSize = matrixRows;
matrixCols = 0;
matrixRows = 0;
virtual bool isMatrix() const { return matrixCols ? true : false; }
virtual bool isArray() const { return arraySizes != 0; }
- int getArraySize() const { return arraySizes->front(); }
- void setArraySizes(TArraySizes s)
+ int getArraySize() const { return arraySizes->sizes.front(); }
+ void setArraySizes(TArraySizes* s)
{
// copy; we don't want distinct types sharing the same descriptor
if (! arraySizes)
*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; }
- TType* getArrayInformationType() { return arrayInformationType; }
+ void changeArraySize(int s) { arraySizes->sizes.front() = s; }
+ void setMaxArraySize (int s) { arraySizes->maxArraySize = s; }
+ int getMaxArraySize () const { return arraySizes->maxArraySize; }
virtual bool isVector() const { return vectorSize > 1; }
virtual bool isScalar() const { return vectorSize == 1; }
const char* getBasicString() const
if (qualifier.storage != EvqTemporary && qualifier.storage != EvqGlobal)
p += snprintf(p, end - p, "%s ", getStorageQualifierString());
if (arraySizes) {
- if (arraySizes->front() == 0)
+ if (arraySizes->sizes.front() == 0)
p += snprintf(p, end - p, "unsized array of ");
else
- p += snprintf(p, end - p, "%d-element array of ", arraySizes->front());
+ p += snprintf(p, end - p, "%d-element array of ", arraySizes->sizes.front());
}
if (qualifier.precision != EpqNone)
p += snprintf(p, end - p, "%s ", getPrecisionQualifierString());
if (isArray())
totalSize *= Max(getArraySize(), getMaxArraySize());
+ // TODO: desktop arrays: it should be ill-defined to get object size if the array is not sized, so the max() above maybe should be an assert
+
return totalSize;
}
{
return sameElementType(right) &&
(arraySizes == 0 && right.arraySizes == 0 ||
- (arraySizes && right.arraySizes && *arraySizes == *right.arraySizes));
+ (arraySizes && right.arraySizes && arraySizes->sizes == right.arraySizes->sizes));
// don't check the qualifier, it's not ever what's being sought after
}
}
protected:
+ // Require consumer to pick between deep copy and shallow copy.
+ TType(const TType& type);
+ TType& operator=(const TType& type);
+
void buildMangledName(TString&);
int getStructSize() const;
TSampler sampler;
TQualifier qualifier;
- TArraySizes arraySizes;
+ TArraySizes* arraySizes;
- TTypeList* structure; // 0 unless this is a struct
- mutable int structureSize; // a cache, updated on first access
- int maxArraySize;
- TType* arrayInformationType;
+ TTypeList* structure; // 0 unless this is a struct
+ mutable int structureSize; // a cache, updated on first access
TString *fieldName; // for structure field names
TString *typeName; // for structure field type name
};
//
class TIntermTyped : public TIntermNode {
public:
- TIntermTyped(const TType& t) : type(t) { }
+ TIntermTyped(const TType& t) { type.shallowCopy(t); }
virtual TIntermTyped* getAsTyped() { return this; }
- virtual void setType(const TType& t) { type = t; }
+ virtual void setType(const TType& t) { type.shallowCopy(t); }
virtual const TType& getType() const { return type; }
- virtual TType* getTypePointer() { return &type; }
+ virtual TType& getWritableType() { return type; }
virtual TBasicType getBasicType() const { return type.getBasicType(); }
virtual TQualifier& getQualifier() { return type.getQualifier(); }
bool CompareStructure(const TType& leftNodeType, TConstUnion* rightUnionArray, TConstUnion* leftUnionArray)
{
if (leftNodeType.isArray()) {
- TType typeWithoutArrayness(leftNodeType);
+ TType typeWithoutArrayness;
+ typeWithoutArrayness.shallowCopy(leftNodeType); // TODO: arrays of arrays: the shallow copy won't work if arrays are shared and dereferenced
typeWithoutArrayness.dereference();
int arraySize = leftNodeType.getArraySize();
// For most cases, the return type matches the argument type, so set that
// up and just code to exceptions below.
- TType returnType(getType());
+ TType returnType;
+ returnType.shallowCopy(getType());
//
// A pair of nodes is to be folded together
unionArray = new TConstUnion[constantNode->getType().getObjectSize()];
for (int i = 0; i < constantNode->getType().getObjectSize(); ++i)
unionArray[i] = *getUnionArrayPointer();
- returnType = node->getType();
+ returnType.shallowCopy(node->getType());
objectSize = constantNode->getType().getObjectSize();
}
newConstArray[column * getMatrixRows() + row].setDConst(sum);
}
}
- returnType = TType(getType().getBasicType(), EvqConst, 0, getMatrixRows(), node->getMatrixCols());
+ returnType.shallowCopy(TType(getType().getBasicType(), EvqConst, 0, getMatrixRows(), node->getMatrixCols()));
break;
case EOpDiv:
newConstArray = new TConstUnion[objectSize];
newConstArray[i].setDConst(sum);
}
- returnType = TType(getBasicType(), EvqConst, getMatrixRows());
+ returnType.shallowCopy(TType(getBasicType(), EvqConst, getMatrixRows()));
break;
case EOpVectorTimesMatrix:
newConstArray[i].setDConst(sum);
}
- returnType = TType(getBasicType(), EvqConst, node->getMatrixCols());
+ returnType.shallowCopy(TType(getBasicType(), EvqConst, node->getMatrixCols()));
break;
case EOpMod:
assert(objectSize == 1);
newConstArray = new TConstUnion[1];
newConstArray->setBConst(*unionArray < *rightUnionArray);
- returnType = TType(EbtBool, EvqConst);
+ returnType.shallowCopy(TType(EbtBool, EvqConst));
break;
case EOpGreaterThan:
assert(objectSize == 1);
newConstArray = new TConstUnion[1];
newConstArray->setBConst(*unionArray > *rightUnionArray);
- returnType = TType(EbtBool, EvqConst);
+ returnType.shallowCopy(TType(EbtBool, EvqConst));
break;
case EOpLessThanEqual:
{
constant.setBConst(*unionArray > *rightUnionArray);
newConstArray = new TConstUnion[1];
newConstArray->setBConst(!constant.getBConst());
- returnType = TType(EbtBool, EvqConst);
+ returnType.shallowCopy(TType(EbtBool, EvqConst));
break;
}
case EOpGreaterThanEqual:
constant.setBConst(*unionArray < *rightUnionArray);
newConstArray = new TConstUnion[1];
newConstArray->setBConst(!constant.getBConst());
- returnType = TType(EbtBool, EvqConst);
+ returnType.shallowCopy(TType(EbtBool, EvqConst));
break;
}
newConstArray = new TConstUnion[1];
newConstArray->setBConst(! boolNodeFlag);
- returnType = TType(EbtBool, EvqConst);
+ returnType.shallowCopy(TType(EbtBool, EvqConst));
break;
case EOpNotEqual:
newConstArray = new TConstUnion[1];
newConstArray->setBConst(! boolNodeFlag);
- returnType = TType(EbtBool, EvqConst);
+ returnType.shallowCopy(TType(EbtBool, EvqConst));
break;
default:
}
TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType);
- newNode->getTypePointer()->getQualifier().storage = EvqConst;
+ newNode->getWritableType().getQualifier().storage = EvqConst;
newNode->setLoc(getLoc());
return newNode;
}
TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, aggrNode->getType());
- newNode->getTypePointer()->getQualifier().storage = EvqConst;
+ newNode->getWritableType().getQualifier().storage = EvqConst;
newNode->setLoc(aggrNode->getLoc());
return newNode;
if (version < FirstProfileVersion || profile == ECompatibilityProfile || (! ForwardCompatibility && profile != EEsProfile && version < 420)) {
TPrecisionQualifier pq = profile == EEsProfile ? EpqMedium : EpqNone;
TType fragData(EbtFloat, EvqFragColor, 4);
- TArraySizes arraySizes = NewPoolTArraySizes();
- arraySizes->push_back(resources.maxDrawBuffers);
+ TArraySizes* arraySizes = NewPoolTArraySizes();
+ arraySizes->setSize(resources.maxDrawBuffers);
fragData.setArraySizes(arraySizes);
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData));
}
TIntermTyped *commaAggregate = growAggregate(left, right, loc);
commaAggregate->getAsAggregate()->setOperator(EOpComma);
commaAggregate->setType(right->getType());
- commaAggregate->getTypePointer()->getQualifier().storage = EvqTemporary;
- commaAggregate->getTypePointer()->getQualifier().precision = right->getTypePointer()->getQualifier().precision;
+ commaAggregate->getWritableType().getQualifier().storage = EvqTemporary;
+ commaAggregate->getWritableType().getQualifier().precision = right->getType().getQualifier().precision;
return commaAggregate;
}
}
setType(operand->getType());
- getTypePointer()->getQualifier().storage = EvqTemporary;
+ getWritableType().getQualifier().storage = EvqTemporary;
return true;
}
if (variable->getType().getQualifier().storage == EvqConst ) {
TConstUnion* constArray = variable->getConstUnionPointer();
- TType t(variable->getType());
- node = intermediate.addConstantUnion(constArray, t, loc);
+ node = intermediate.addConstantUnion(constArray, variable->getType(), loc);
} else
node = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), loc);
}
if (base->isArray()) {
if (base->getType().getArraySize() == 0) {
if (base->getType().getMaxArraySize() <= index->getAsConstantUnion()->getUnionArrayPointer()->getIConst())
- arraySetMaxSize(base->getAsSymbolNode(), base->getTypePointer(), index->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), true, loc);
- else
- arraySetMaxSize(base->getAsSymbolNode(), base->getTypePointer(), 0, false, loc);
+ arraySetMaxSize(loc, base->getAsSymbolNode(), index->getAsConstantUnion()->getUnionArrayPointer()->getIConst() + 1);
} else if ( index->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= base->getType().getArraySize() ||
index->getAsConstantUnion()->getUnionArrayPointer()->getIConst() < 0)
error(loc, "", "[", "array index out of range '%d'", index->getAsConstantUnion()->getUnionArrayPointer()->getIConst());
unionArray->setDConst(0.0);
result = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), loc);
} else {
- TType newType(base->getType());
+ TType newType;
+ newType.shallowCopy(base->getType());
if (base->getType().getQualifier().storage == EvqConst && index->getQualifier().storage == EvqConst)
newType.getQualifier().storage = EvqConst;
newType.dereference();
result->setType(*(*fields)[i].type);
// change the qualifier of the return type, not of the structure field
// as the structure definition is shared between various structures.
- result->getTypePointer()->getQualifier().storage = EvqConst;
+ result->getWritableType().getQualifier().storage = EvqConst;
}
} else {
TConstUnion *unionArray = new TConstUnion[1];
//
bool TParseContext::constructorError(TSourceLoc loc, TIntermNode* node, TFunction& function, TOperator op, TType& type)
{
- type = function.getReturnType();
+ type.shallowCopy(function.getReturnType());
bool constructingMatrix = false;
switch(op) {
return false;
}
-bool TParseContext::insertBuiltInArrayAtGlobalLevel()
-{
- TString *name = NewPoolTString("gl_TexCoord");
- TSymbol* symbol = symbolTable.find(*name);
- if (! symbol) {
- // assume it was not added due to version/profile
-
- return false;
- }
- const TVariable* variable = symbol->getAsVariable();
-
- if (! variable) {
- infoSink.info.message(EPrefixInternalError, "variable expected");
- return true;
- }
-
- TVariable* newVariable = new TVariable(name, variable->getType());
-
- if (! symbolTable.insert(*newVariable)) {
- delete newVariable;
- infoSink.info.message(EPrefixInternalError, "inserting new symbol");
- return true;
- }
-
- return false;
-}
-
//
// Do size checking for an array type's size.
//
//
// Require array to have size
//
-void TParseContext::arraySizeRequiredCheck(TSourceLoc loc, int& size)
+void TParseContext::arraySizeRequiredCheck(TSourceLoc loc, int size)
{
if (size == 0) {
error(loc, "array size required", "", "");
profileRequires(loc, ECompatibilityProfile, 430, 0, "arrays of arrays");
}
-void TParseContext::arrayDimCheck(TSourceLoc loc, TArraySizes sizes1, TArraySizes sizes2)
+void TParseContext::arrayDimCheck(TSourceLoc loc, TArraySizes* sizes1, TArraySizes* sizes2)
{
if (sizes1 && sizes2 ||
- sizes1 && sizes1->size() > 1 ||
- sizes2 && sizes2->size() > 1)
+ sizes1 && sizes1->isArrayOfArrays() ||
+ sizes2 && sizes2->isArrayOfArrays())
arrayDimError(loc);
}
-void TParseContext::arrayDimCheck(TSourceLoc loc, const TType* type, TArraySizes sizes2)
+void TParseContext::arrayDimCheck(TSourceLoc loc, const TType* type, TArraySizes* sizes2)
{
if (type && type->isArray() && sizes2 ||
- sizes2 && sizes2->size() > 1)
+ sizes2 && sizes2->isArrayOfArrays())
arrayDimError(loc);
}
// However, reserved arrays cannot be modified in a shared symbol table, so add a new
// one at a non-shared level in the table.
//
+ // Redeclarations have to take place at the same scope; otherwise they are hiding declarations
+ //
bool currentScope;
TSymbol* symbol = symbolTable.find(identifier, 0, ¤tScope);
return;
}
- TType* t = variable->getArrayInformationType();
- while (t != 0) {
- if (t->getMaxArraySize() > type.arraySizes->front()) {
- error(loc, "higher index value already used for the array", identifier.c_str(), "");
- return;
- }
- t->setArraySizes(type.arraySizes);
- t = t->getArrayInformationType();
- }
+ // For read-only built-ins, add a new variable for holding the declared array size of an implicitly-sized shared array.
+ if (variable->isReadOnly())
+ variable = symbolTable.copyUp(variable);
+ // TODO: desktop unsized arrays: include modified built-in arrays (gl_TexCoord) in the linker objects subtree
+
variable->getWritableType().setArraySizes(type.arraySizes);
}
voidErrorCheck(loc, identifier, type);
}
-bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, bool updateFlag, TSourceLoc loc)
+bool TParseContext::arraySetMaxSize(TSourceLoc loc, TIntermSymbol *node, int size)
{
TSymbol* symbol = symbolTable.find(node->getName());
if (symbol == 0) {
return true;
}
- // There are multiple copies of the array type tagging results of operations.
- // Chain these together, so they can all reflect the final size.
- type->setArrayInformationType(variable->getArrayInformationType());
- variable->updateArrayInformationType(type);
-
- // special casing to test index value of gl_TexCoord. If the accessed index is >= gl_MaxTextureCoords
- // its an error
- if (node->getName() == "gl_TexCoord") {
- TSymbol* texCoord = symbolTable.find("gl_MaxTextureCoords");
- if (! texCoord || ! texCoord->getAsVariable()) {
- infoSink.info.message(EPrefixInternalError, "gl_MaxTextureCoords not defined", loc);
- return true;
- }
+ // TODO: desktop linker: make this a link-time check (note if it's here, an explicit declaration skips it)
+ //if (node->getName() == "gl_TexCoord") {
+ // TSymbol* texCoord = symbolTable.find("gl_MaxTextureCoords");
+ // if (! texCoord || ! texCoord->getAsVariable()) {
+ // infoSink.info.message(EPrefixInternalError, "gl_MaxTextureCoords not defined", loc);
+ // return true;
+ // }
- int texCoordValue = texCoord->getAsVariable()->getConstUnionPointer()[0].getIConst();
- if (texCoordValue <= size) {
- error(loc, "", "[", "gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords", "");
- return true;
- }
- }
+ // int texCoordValue = texCoord->getAsVariable()->getConstUnionPointer()[0].getIConst();
+ // if (texCoordValue <= size) {
+ // error(loc, "", "[", "gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords", "");
+ // return true;
+ // }
+ //}
- // We don't want to update the maxArraySize when this flag is not set, we just want to include this
- // node type in the chain of node types so that it's updated when a higher maxArraySize comes in.
- if (! updateFlag)
- return false;
+ // For read-only built-ins, add a new variable for holding the maximum array size of an implicitly-sized shared array.
+ if (variable->isReadOnly())
+ variable = symbolTable.copyUp(variable);
- size++;
variable->getWritableType().setMaxArraySize(size);
- type->setMaxArraySize(size);
- TType* tt = type;
-
- while(tt->getArrayInformationType() != 0) {
- tt = tt->getArrayInformationType();
- tt->setMaxArraySize(size);
- }
return false;
}
if (op == EOpConstructStruct)
memberTypes = type.getStruct()->begin();
- TType elementType(type);
+ TType elementType;
+ elementType.shallowCopy(type);
if (type.isArray())
- elementType.dereference();
+ elementType.dereference(); // TODO: arrays of arrays: shallow copy won't work if sharing same array structure and then doing a dereference
bool singleArg;
if (aggrNode) {
//
// Do everything needed to add an interface block.
//
-void TParseContext::addBlock(TSourceLoc loc, TTypeList& typeList, const TString* instanceName, TArraySizes arraySizes)
+void TParseContext::addBlock(TSourceLoc loc, TTypeList& typeList, const TString* instanceName, TArraySizes* arraySizes)
{
// First, error checks
return;
if (profile == EEsProfile && arraySizes)
- arraySizeRequiredCheck(loc, arraySizes->front());
+ arraySizeRequiredCheck(loc, arraySizes->getSize());
if (currentBlockDefaults.storage == EvqUniform) {
requireProfile(loc, (EProfileMask)(~ENoProfileMask), "uniform block");
// For an identifier that is already declared, add more qualification to it.
void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, const TString& identifier)
{
- bool sharedLevel;
- TSymbol* existing = symbolTable.find(identifier, 0, 0, &sharedLevel);
+ TSymbol* existing = symbolTable.find(identifier);
TVariable* variable = existing ? existing->getAsVariable() : 0;
if (! variable) {
error(loc, "identifier not previously declared", identifier.c_str(), "");
return;
}
- //
- // Don't change a shared variable; rather add a new one at the current scope.
- //
- if (sharedLevel) {
- variable = new TVariable(&variable->getName(), variable->getType());
- symbolTable.insert(*variable);
- }
+ // For read-only built-ins, add a new variable for holding the modified qualifier.
+ if (variable->isReadOnly())
+ variable = symbolTable.copyUp(variable);
if (qualifier.invariant)
variable->getWritableType().getQualifier().invariant = true;
TIntermTyped* typedNode;
TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
int arraySize = node->getType().getArraySize();
- TType arrayElementType(node->getType());
- arrayElementType.dereference();
+ TType arrayElementType;
+ arrayElementType.shallowCopy(node->getType());
+ arrayElementType.dereference(); // TODO: arrays of arrays: shallow copy won't work if sharing same array structure and then doing a dereference
if (index >= node->getType().getArraySize() || index < 0) {
error(loc, "", "[", "array index '%d' out of range", index);
bool constructorError(TSourceLoc, TIntermNode*, TFunction&, TOperator, TType&);
void arraySizeCheck(TSourceLoc, TIntermTyped* expr, int& size);
bool arrayQualifierError(TSourceLoc, const TPublicType&);
- void arraySizeRequiredCheck(TSourceLoc, int& size);
+ void arraySizeRequiredCheck(TSourceLoc, int size);
void arrayDimError(TSourceLoc);
- void arrayDimCheck(TSourceLoc, TArraySizes sizes1, TArraySizes sizes2);
- void arrayDimCheck(TSourceLoc, const TType*, TArraySizes);
+ void arrayDimCheck(TSourceLoc, TArraySizes* sizes1, TArraySizes* sizes2);
+ void arrayDimCheck(TSourceLoc, const TType*, TArraySizes*);
void arrayCheck(TSourceLoc, TString& identifier, const TPublicType&, TVariable*& variable);
- bool insertBuiltInArrayAtGlobalLevel();
bool voidErrorCheck(TSourceLoc, const TString&, const TPublicType&);
void boolCheck(TSourceLoc, const TIntermTyped*);
void boolCheck(TSourceLoc, const TPublicType&);
TIntermTyped* addConstructor(TIntermNode*, const TType&, TOperator, TFunction*, TSourceLoc);
TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc);
TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermNode*, TSourceLoc, bool subset);
- void addBlock(TSourceLoc, TTypeList& typeList, const TString* instanceName = 0, TArraySizes arraySizes = 0);
+ void addBlock(TSourceLoc, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0);
void addQualifierToExisting(TSourceLoc, TQualifier, const TString& identifier);
void addQualifierToExisting(TSourceLoc, TQualifier, TIdentifierList&);
void updateQualifierDefaults(TQualifier);
TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc);
TIntermTyped* addConstStruct(TString& , TIntermTyped*, TSourceLoc);
- bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, TSourceLoc);
+ bool arraySetMaxSize(TSourceLoc, TIntermSymbol*, int);
void requireProfile(TSourceLoc, EProfileMask profileMask, const char *featureDesc);
void requireStage(TSourceLoc, EShLanguageMask languageMask, const char *featureDesc);
if (ReservedSet->find(tokenText) != ReservedSet->end())
return reservedWord();
- keyword = (*KeywordMap)[tokenText];
- if (keyword == 0) {
+ std::map<std::string, int>::const_iterator it = KeywordMap->find(tokenText);
+ if (it == KeywordMap->end()) {
// Should have an identifier of some sort
return identifierOrType();
}
+ keyword = it->second;
field = false;
switch (keyword) {
if (! symbolTable.atGlobalLevel())
parseContext.infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
- if (parseContext.insertBuiltInArrayAtGlobalLevel())
- success = false;
-
bool ret = parseContext.parseShaderStrings(ppContext, const_cast<char**>(shaderStrings), lengths, numStrings);
if (! ret)
success = false;
case EbtStruct:
mangledName += "struct-";
if (typeName)
- mangledName += *typeName;
+ mangledName += *typeName;
for (unsigned int i = 0; i < structure->size(); ++i) {
mangledName += '-';
(*structure)[i].type->buildMangledName(mangledName);
}
if (arraySizes) {
- const int maxSize = 11;
+ const int maxSize = 11;
char buf[maxSize];
- snprintf(buf, maxSize, "%d", arraySizes->front());
+ snprintf(buf, maxSize, "%d", arraySizes->sizes.front());
mangledName += '[';
mangledName += buf;
mangledName += ']';
//
TFunction::~TFunction()
{
- for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i)
- delete (*i).type;
+ for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i)
+ delete (*i).type;
}
//
//
TSymbolTableLevel::~TSymbolTableLevel()
{
- for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
- delete (*it).second;
+ for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
+ delete (*it).second;
delete [] defaultPrecision;
}
void TSymbolTableLevel::readOnly()
{
for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
- (*it).second->readOnly();
+ (*it).second->makeReadOnly();
}
+//
+// Copy a symbol, but the copy is writable; call readOnly() afterward if that's not desired.
+//
TSymbol::TSymbol(const TSymbol& copyOf)
{
- name = NewPoolTString(copyOf.name->c_str());
- uniqueId = copyOf.uniqueId;
+ name = NewPoolTString(copyOf.name->c_str());
+ uniqueId = copyOf.uniqueId;
+ writable = true;
}
TVariable::TVariable(const TVariable& copyOf, TStructureMap& remapper) : TSymbol(copyOf)
{
- type.copyType(copyOf.type, remapper);
- userType = copyOf.userType;
- // for builtIn symbol table level, unionArray and arrayInformation pointers should be NULL
- assert(copyOf.arrayInformationType == 0);
- arrayInformationType = 0;
-
- if (copyOf.unionArray) {
- assert(!copyOf.type.getStruct());
- assert(copyOf.type.getObjectSize() == 1);
- unionArray = new TConstUnion[1];
+ type.deepCopy(copyOf.type, remapper);
+ userType = copyOf.userType;
+
+ if (copyOf.unionArray) {
+ assert(!copyOf.type.getStruct());
+ assert(copyOf.type.getObjectSize() == 1);
+ unionArray = new TConstUnion[1];
unionArray[0] = copyOf.unionArray[0];
- } else
- unionArray = 0;
+ } else
+ unionArray = 0;
}
TVariable* TVariable::clone(TStructureMap& remapper)
{
- TVariable *variable = new TVariable(*this, remapper);
+ TVariable *variable = new TVariable(*this, remapper);
- return variable;
+ return variable;
}
TFunction::TFunction(const TFunction& copyOf, const TStructureMap& remapper) : TSymbol(copyOf)
{
- for (unsigned int i = 0; i < copyOf.parameters.size(); ++i) {
- TParameter param;
- parameters.push_back(param);
- parameters.back().copyParam(copyOf.parameters[i], remapper);
- }
-
- returnType.copyType(copyOf.returnType, remapper);
- mangledName = copyOf.mangledName;
- op = copyOf.op;
- defined = copyOf.defined;
+ for (unsigned int i = 0; i < copyOf.parameters.size(); ++i) {
+ TParameter param;
+ parameters.push_back(param);
+ parameters.back().copyParam(copyOf.parameters[i], remapper);
+ }
+
+ returnType.deepCopy(copyOf.returnType, remapper);
+ mangledName = copyOf.mangledName;
+ op = copyOf.op;
+ defined = copyOf.defined;
}
TFunction* TFunction::clone(TStructureMap& remapper)
{
- TFunction *function = new TFunction(*this, remapper);
+ TFunction *function = new TFunction(*this, remapper);
- return function;
+ return function;
}
TAnonMember* TAnonMember::clone(TStructureMap& remapper)
TSymbolTableLevel* TSymbolTableLevel::clone(TStructureMap& remapper)
{
- TSymbolTableLevel *symTableLevel = new TSymbolTableLevel();
+ TSymbolTableLevel *symTableLevel = new TSymbolTableLevel();
symTableLevel->anonId = anonId;
- tLevel::iterator iter;
- for (iter = level.begin(); iter != level.end(); ++iter)
- symTableLevel->insert(*iter->second->clone(remapper));
+ tLevel::iterator iter;
+ for (iter = level.begin(); iter != level.end(); ++iter)
+ symTableLevel->insert(*iter->second->clone(remapper));
- return symTableLevel;
+ return symTableLevel;
}
void TSymbolTable::copyTable(const TSymbolTable& copyOf)
{
assert(adoptedLevels == copyOf.adoptedLevels);
- TStructureMap remapper;
- uniqueId = copyOf.uniqueId;
+ TStructureMap remapper;
+ uniqueId = copyOf.uniqueId;
noBuiltInRedeclarations = copyOf.noBuiltInRedeclarations;
for (unsigned int i = copyOf.adoptedLevels; i < copyOf.table.size(); ++i)
- table.push_back(copyOf.table[i]->clone(remapper));
+ table.push_back(copyOf.table[i]->clone(remapper));
}
} // end namespace glslang
int getUniqueId() const { return uniqueId; }
virtual void dump(TInfoSink &infoSink) const = 0;
- void readOnly() { writable = false; }
+ bool isReadOnly() { return ! writable; }
+ void makeReadOnly() { writable = false; }
protected:
explicit TSymbol(const TSymbol&);
//
class TVariable : public TSymbol {
public:
- TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0), arrayInformationType(0) { }
+ TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), userType(uT), unionArray(0) { type.shallowCopy(t); }
virtual TVariable* clone(TStructureMap& remapper);
virtual ~TVariable() { }
TType& getWritableType() { assert(writable); return type; }
const TType& getType() const { return type; }
bool isUserType() const { return userType; }
- void updateArrayInformationType(TType *t) { assert(writable); arrayInformationType = t; }
- TType* getArrayInformationType() { assert(writable); return arrayInformationType; }
virtual void dump(TInfoSink &infoSink) const;
- TConstUnion* getConstUnionPointer() {
+ TConstUnion* getConstUnionPointer()
+ {
if (!unionArray)
unionArray = new TConstUnion[type.getObjectSize()];
}
protected:
- explicit TVariable(TVariable&);
- TVariable(const TVariable&, TStructureMap& remapper);
- TVariable& operator=(TVariable&);
+ explicit TVariable(const TVariable&);
+ TVariable(const TVariable&, TStructureMap& remapper);
+ TVariable& operator=(const TVariable&);
TType type;
bool userType;
// we are assuming that Pool Allocator will free the memory allocated to unionArray
// when this object is destroyed
TConstUnion *unionArray;
- TType *arrayInformationType; // this is used for updating maxArraySize in all the references to a given symbol
};
//
public:
explicit TFunction(TOperator o) :
TSymbol(0),
- returnType(TType(EbtVoid)),
op(o),
defined(false) { }
TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull) :
TSymbol(name),
- returnType(retType),
mangledName(*name + '('),
op(tOp),
- defined(false) { }
+ defined(false) { returnType.shallowCopy(retType); }
virtual TFunction* clone(TStructureMap& remapper);
virtual ~TFunction();
return table[currentLevel()]->insert(symbol);
}
- TSymbol* find(const TString& name, bool* builtIn = 0, bool *currentScope = 0, bool *sharedLevel = 0)
+ //
+ // To copy a variable from a shared level up to the current level, so it can be
+ // modified without impacting other users of the shared table.
+ //
+ TVariable* copyUp(TVariable* shared)
+ {
+ TVariable* variable = shared->clone(remapper);
+ variable->setUniqueId(shared->getUniqueId());
+ table[currentLevel()]->insert(*variable);
+
+ return variable;
+ }
+
+ TSymbol* find(const TString& name, bool* builtIn = 0, bool *currentScope = 0)
{
int level = currentLevel();
TSymbol* symbol;
if (builtIn)
*builtIn = isBuiltInLevel(level);
if (currentScope)
- *currentScope = level == currentLevel();
- if (sharedLevel)
- *sharedLevel = isSharedLevel(level);
+ *currentScope = isGlobalLevel(currentLevel()) || level == currentLevel(); // consider shared levels as "current scope" WRT user globals
return symbol;
}
int uniqueId; // for unique identification in code generation
bool noBuiltInRedeclarations;
unsigned int adoptedLevels;
+ TStructureMap remapper; // for now, dummy for copyUp(), which is not yet used for structures
};
} // end namespace glslang
glslang::TParameter param;\r
glslang::TTypeLoc typeLine;\r
glslang::TTypeList* typeList;\r
- glslang::TArraySizes arraySizes;\r
+ glslang::TArraySizes* arraySizes;\r
glslang::TIdentifierList* identifierList;\r
};\r
} interm;\r
\r
function_call_header_with_parameters\r
: function_call_header assignment_expression {\r
- TParameter param = { 0, new TType($2->getType()) };\r
+ TParameter param = { 0, new TType };\r
+ param.type->shallowCopy($2->getType());\r
$1.function->addParameter(param);\r
$$.function = $1.function;\r
$$.intermNode = $2;\r
}\r
| function_call_header_with_parameters COMMA assignment_expression {\r
- TParameter param = { 0, new TType($3->getType()) };\r
+ TParameter param = { 0, new TType };\r
+ param.type->shallowCopy($3->getType());\r
$1.function->addParameter(param);\r
$$.function = $1.function;\r
$$.intermNode = parseContext.intermediate.growAggregate($1.intermNode, $3, $2.loc);\r
if ($1.arraySizes) {\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->front());\r
+ parseContext.arraySizeRequiredCheck($1.loc, $1.arraySizes->getSize());\r
}\r
if ($1.basicType == EbtVoid) {\r
parseContext.error($2.loc, "illegal use of type 'void'", $2.string->c_str(), "");\r
if ($1.arraySizes) {\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->front());\r
+ parseContext.arraySizeRequiredCheck($1.loc, $1.arraySizes->getSize());\r
}\r
parseContext.arrayDimCheck($2.loc, $1.arraySizes, $3.arraySizes);\r
\r
- parseContext.arraySizeRequiredCheck($3.loc, $3.arraySizes->front());\r
+ parseContext.arraySizeRequiredCheck($3.loc, $3.arraySizes->getSize());\r
parseContext.reservedErrorCheck($2.loc, *$2.string);\r
\r
$1.arraySizes = $3.arraySizes;\r
| init_declarator_list COMMA IDENTIFIER array_specifier {\r
parseContext.nonInitConstCheck($3.loc, *$3.string, $1.type);\r
if (parseContext.profile == EEsProfile)\r
- parseContext.arraySizeRequiredCheck($4.loc, $4.arraySizes->front());\r
+ parseContext.arraySizeRequiredCheck($4.loc, $4.arraySizes->getSize());\r
parseContext.arrayDimCheck($3.loc, $1.type.arraySizes, $4.arraySizes);\r
\r
$$ = $1;\r
$$.intermAggregate = 0;\r
parseContext.nonInitConstCheck($2.loc, *$2.string, $1); \r
if (parseContext.profile == EEsProfile)\r
- parseContext.arraySizeRequiredCheck($3.loc, $3.arraySizes->front()); \r
+ parseContext.arraySizeRequiredCheck($3.loc, $3.arraySizes->getSize()); \r
parseContext.arrayDimCheck($2.loc, $1.arraySizes, $3.arraySizes);\r
\r
$$.type = $1;\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->front());\r
+ parseContext.arraySizeRequiredCheck($1.loc, $1.arraySizes->getSize());\r
}\r
\r
parseContext.precisionQualifierCheck($$.loc, $$);\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->front());\r
+ parseContext.arraySizeRequiredCheck($2.loc, $2.arraySizes->getSize());\r
}\r
\r
if ($2.arraySizes && parseContext.arrayQualifierError($2.loc, $1))\r
: LEFT_BRACKET RIGHT_BRACKET {\r
$$.loc = $1.loc;\r
$$.arraySizes = NewPoolTArraySizes();\r
- $$.arraySizes->push_back(0);\r
+ $$.arraySizes->setSize(0);\r
}\r
| LEFT_BRACKET constant_expression RIGHT_BRACKET {\r
$$.loc = $1.loc;\r
\r
int size;\r
parseContext.arraySizeCheck($2->getLoc(), $2, size);\r
- $$.arraySizes->push_back(size);\r
+ $$.arraySizes->setSize(size);\r
}\r
| array_specifier LEFT_BRACKET RIGHT_BRACKET {\r
$$ = $1;\r
- $$.arraySizes->push_back(0);\r
+ $$.arraySizes->setSize(0);\r
}\r
| array_specifier LEFT_BRACKET constant_expression RIGHT_BRACKET {\r
$$ = $1;\r
\r
int size;\r
parseContext.arraySizeCheck($3->getLoc(), $3, size);\r
- $$.arraySizes->push_back(size);\r
+ $$.arraySizes->setSize(size);\r
}\r
;\r
\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->front());\r
+ parseContext.arraySizeRequiredCheck($1.loc, $1.arraySizes->getSize());\r
}\r
\r
$$ = $2;\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->front());\r
+ parseContext.arraySizeRequiredCheck($2.loc, $2.arraySizes->getSize());\r
}\r
\r
$$ = $3;\r
}\r
| IDENTIFIER array_specifier { \r
if (parseContext.profile == EEsProfile)\r
- parseContext.arraySizeRequiredCheck($2.loc, $2.arraySizes->front());\r
+ parseContext.arraySizeRequiredCheck($2.loc, $2.arraySizes->getSize());\r
parseContext.arrayDimCheck($1.loc, $2.arraySizes, 0);\r
\r
$$.type = new TType(EbtVoid);\r