From 9d30218fb6dba2ea0bc922bd9d0ecd038694c4d1 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Fri, 11 Oct 2013 17:29:19 +0000 Subject: [PATCH] Generalize the symbol hierarchy to transparently handle anonymous-block members better. git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23469 e7fa87d3-cd2b-0410-9028-fcbf551c1848 --- Todo.txt | 1 + glslang/MachineIndependent/Intermediate.cpp | 17 +- glslang/MachineIndependent/ParseHelper.cpp | 179 +++++++++--------- glslang/MachineIndependent/ParseHelper.h | 6 +- glslang/MachineIndependent/SymbolTable.cpp | 33 +++- glslang/MachineIndependent/SymbolTable.h | 130 ++++++++----- glslang/MachineIndependent/glslang.y | 2 +- .../MachineIndependent/localintermediate.h | 4 +- 8 files changed, 217 insertions(+), 155 deletions(-) diff --git a/Todo.txt b/Todo.txt index 68b12126..a989f64f 100644 --- a/Todo.txt +++ b/Todo.txt @@ -24,6 +24,7 @@ Link Validation + Non ES: value checking of global const initializers + Non ES: value checking of uniform initializers + Non ES: location match + - gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords - location aliasing/overlap (except desktop vertex shader inputs) - 1.0: count the number of uniforms and varyings, compare against limits + recursion for functions diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp index cdff8684..9c184143 100644 --- a/glslang/MachineIndependent/Intermediate.cpp +++ b/glslang/MachineIndependent/Intermediate.cpp @@ -885,6 +885,11 @@ void TIntermediate::addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguag treeRoot = growAggregate(treeRoot, linkage); } +// +// Add the given name or symbol to the list of nodes at the end of the tree used +// for link-time checking and external linkage. +// + void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable& symbolTable, const TString& name) { TSymbol* symbol = symbolTable.find(name); @@ -892,10 +897,16 @@ void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTabl addSymbolLinkageNode(linkage, *symbol->getAsVariable()); } -void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, const TVariable& variable) +void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol& symbol) { - TIntermSymbol* node = new TIntermSymbol(variable.getUniqueId(), variable.getName(), variable.getType()); - node->setConstArray(variable.getConstArray()); + const TVariable* variable = symbol.getAsVariable(); + if (! variable) { + // This must be a member of an anonymous block, and we need to add the whole block + const TAnonMember* anon = symbol.getAsAnonMember(); + variable = &anon->getAnonContainer(); + } + TIntermSymbol* node = new TIntermSymbol(variable->getUniqueId(), variable->getName(), variable->getType()); + node->setConstArray(variable->getConstArray()); linkage = growAggregate(linkage, node); } diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index d981df3b..274aeea6 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -473,11 +473,10 @@ TIntermTyped* TParseContext::handleBracketDereference(TSourceLoc loc, TIntermTyp (base->isMatrix() && base->getType().getMatrixCols() <= indexValue))) error(loc, "", "[", "index out of range '%d'", index->getAsConstantUnion()->getConstArray()[0].getIConst()); if (base->isArray()) { - if (base->getType().getArraySize() == 0) { - if (base->getType().getMaxArraySize() <= index->getAsConstantUnion()->getConstArray()[0].getIConst()) - arraySetMaxSize(loc, base->getAsSymbolNode(), index->getAsConstantUnion()->getConstArray()[0].getIConst() + 1); - } else if ( index->getAsConstantUnion()->getConstArray()[0].getIConst() >= base->getType().getArraySize() || - index->getAsConstantUnion()->getConstArray()[0].getIConst() < 0) + if (base->getType().getArraySize() == 0) + updateMaxArraySize(loc, base, index->getAsConstantUnion()->getConstArray()[0].getIConst()); + else if (index->getAsConstantUnion()->getConstArray()[0].getIConst() >= base->getType().getArraySize() || + index->getAsConstantUnion()->getConstArray()[0].getIConst() < 0) error(loc, "", "[", "array index out of range '%d'", index->getAsConstantUnion()->getConstArray()[0].getIConst()); } result = intermediate.addIndex(EOpIndexDirect, base, index, loc); @@ -627,8 +626,8 @@ TFunction* TParseContext::handleFunctionDeclarator(TSourceLoc loc, TFunction& fu requireNotRemoved(loc, EEsProfile, 300, "redeclaration of built-in function"); const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0; if (prevDec) { - if (prevDec->getReturnType() != function.getReturnType()) { - error(loc, "overloaded functions must have the same return type", function.getReturnType().getCompleteTypeString().c_str(), ""); + if (prevDec->getType() != function.getType()) { + error(loc, "overloaded functions must have the same return type", function.getType().getCompleteTypeString().c_str(), ""); } for (int i = 0; i < prevDec->getParamCount(); ++i) { if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage) @@ -679,7 +678,7 @@ TIntermAggregate* TParseContext::handleFunctionPrototype(TSourceLoc loc, TFuncti // // Remember the return type for later checking for RETURN statements. // - currentFunctionType = &(prevDec->getReturnType()); + currentFunctionType = &(prevDec->getType()); } else currentFunctionType = new TType(EbtVoid); functionReturnsValue = false; @@ -690,8 +689,8 @@ TIntermAggregate* TParseContext::handleFunctionPrototype(TSourceLoc loc, TFuncti if (function.getName() == "main") { if (function.getParamCount() > 0) error(loc, "function cannot take any parameter(s)", function.getName().c_str(), ""); - if (function.getReturnType().getBasicType() != EbtVoid) - error(loc, "", function.getReturnType().getCompleteTypeString().c_str(), "main function cannot return a value"); + if (function.getType().getBasicType() != EbtVoid) + error(loc, "", function.getType().getCompleteTypeString().c_str(), "main function cannot return a value"); intermediate.addMainCount(); } @@ -798,7 +797,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal op = fnCandidate->getBuiltInOp(); if (builtIn && op != EOpNull) { // A function call mapped to a built-in operation. - result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, intermNode, fnCandidate->getReturnType()); + result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, intermNode, fnCandidate->getType()); if (result == 0) { error(intermNode->getLoc(), " wrong operand type", "Internal Error", "built in unary operator function. Type: %s", @@ -807,7 +806,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal } } else { // This is a function call not mapped to built-in operation - result = intermediate.setAggregateOperator(intermAggregate, EOpFunctionCall, fnCandidate->getReturnType(), loc); + result = intermediate.setAggregateOperator(intermAggregate, EOpFunctionCall, fnCandidate->getType(), loc); result->getAsAggregate()->setName(fnCandidate->getMangledName()); // this is how we know whether the given function is a built-in function or a user-defined function @@ -830,7 +829,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal } // built-in texturing functions get their return value precision from the precision of the sampler - if (builtIn && fnCandidate->getReturnType().getQualifier().precision == EpqNone && + if (builtIn && fnCandidate->getType().getQualifier().precision == EpqNone && fnCandidate->getParamCount() > 0 && (*fnCandidate)[0].type->getBasicType() == EbtSampler) result->getQualifier().precision = result->getAsAggregate()->getSequence()[0]->getAsTyped()->getQualifier().precision; } @@ -1228,7 +1227,7 @@ bool TParseContext::reservedErrorCheck(TSourceLoc loc, const TString& identifier // bool TParseContext::constructorError(TSourceLoc loc, TIntermNode* node, TFunction& function, TOperator op, TType& type) { - type.shallowCopy(function.getReturnType()); + type.shallowCopy(function.getType()); bool constructingMatrix = false; switch(op) { @@ -1713,89 +1712,86 @@ void TParseContext::arrayDimCheck(TSourceLoc loc, const TType* type, TArraySizes // // size == 0 means no specified size. // -void TParseContext::declareArray(TSourceLoc loc, TString& identifier, const TType& type, TVariable*& variable, bool& newDeclaration) +void TParseContext::declareArray(TSourceLoc loc, TString& identifier, const TType& type, TSymbol*& symbol, bool& newDeclaration) { - // - // Don't check for reserved word use until after we know it's not in the symbol table, - // because reserved arrays can be redeclared. - // - // 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 - // - - if (! variable) { + if (! symbol) { bool currentScope; - TSymbol* symbol = symbolTable.find(identifier, 0, ¤tScope); + symbol = symbolTable.find(identifier, 0, ¤tScope); if (symbol == 0 || ! currentScope) { - variable = new TVariable(&identifier, type); - symbolTable.insert(*variable); + // + // Successfully process a new definition. + // (Redeclarations have to take place at the same scope; otherwise they are hiding declarations) + // + symbol = new TVariable(&identifier, type); + symbolTable.insert(*symbol); newDeclaration = true; - return; } - variable = symbol->getAsVariable(); + if (symbol->getAsAnonMember()) { + error(loc, "cannot redeclare a user-block member array", identifier.c_str(), ""); + return; + } } - if (! variable) { + // + // Process a redeclaration. + // + + if (! symbol) { error(loc, "array variable name expected", identifier.c_str(), ""); return; } - if (! variable->getType().isArray()) { + TType& newType = symbol->getWritableType(); + + if (! newType.isArray()) { error(loc, "redeclaring non-array as array", identifier.c_str(), ""); return; } - if (variable->getType().getArraySize() > 0) { + if (newType.getArraySize() > 0) { error(loc, "redeclaration of array with size", identifier.c_str(), ""); return; } - if (! variable->getType().sameElementType(type)) { - error(loc, "redeclaration of array with a different type", identifier.c_str(), ""); + if (! newType.sameElementType(type)) { + error(loc, "redeclaration of array with a different newType", identifier.c_str(), ""); return; } - variable->getWritableType().shareArraySizes(type); + newType.shareArraySizes(type); } -bool TParseContext::arraySetMaxSize(TSourceLoc loc, TIntermSymbol *node, int size) +void TParseContext::updateMaxArraySize(TSourceLoc loc, TIntermNode *node, int index) { - TSymbol* symbol = symbolTable.find(node->getName()); - if (symbol == 0) { - error(loc, " undeclared identifier", node->getName().c_str(), ""); - return true; + TIntermSymbol* symbolNode = node->getAsSymbolNode(); + if (! symbolNode) { + // TODO: functionality: unsized arrays: handle members of blocks + return; } - TVariable* variable = symbol->getAsVariable(); - if (! variable) { - error(loc, "array variable name expected", node->getName().c_str(), ""); - return true; + // maybe there is nothing to do... + // TODO: functionality: unsized arrays: is the node sharing the array type with the symbol table? + if (symbolNode->getType().getMaxArraySize() > index) + return; + + // something to do... + + TSymbol* symbol = symbolTable.find(symbolNode->getName()); + assert(symbol); + if (symbol == 0) + return; + + if (symbol->getAsFunction()) { + error(loc, "array variable name expected", symbolNode->getName().c_str(), ""); + return; } - // 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()->getConstArray()[0].getIConst(); - // if (texCoordValue <= size) { - // error(loc, "", "[", "gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords", ""); - // return true; - // } - //} - // 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); + // TODO: functionality: unsized arrays: is this new array type shared with the node? + if (symbol->isReadOnly()) + symbol = symbolTable.copyUp(symbol); - variable->getWritableType().setMaxArraySize(size); - - return false; + symbol->getWritableType().setMaxArraySize(index + 1); } // @@ -1822,9 +1818,7 @@ void TParseContext::nonInitConstCheck(TSourceLoc loc, TString& identifier, TType // // Returns a redeclared and type-modified variable if a redeclarated occurred. // -// Will emit -// -TVariable* TParseContext::redeclareBuiltin(TSourceLoc loc, const TString& identifier, bool& newDeclaration) +TSymbol* TParseContext::redeclareBuiltin(TSourceLoc loc, const TString& identifier, bool& newDeclaration) { if (profile == EEsProfile || identifier.compare(0, 3, "gl_") != 0 || symbolTable.atBuiltInLevel()) return 0; @@ -1853,21 +1847,19 @@ TVariable* TParseContext::redeclareBuiltin(TSourceLoc loc, const TString& identi if (! symbol) return 0; - TVariable* variable = symbol->getAsVariable(); - // If it wasn't at a built-in level, then it's already been redeclared; // that is, this is a redeclaration of a redeclaration, reuse that initial // redeclaration. Otherwise, make the new one. if (builtIn) { // Copy the symbol up to make a writable version newDeclaration = true; - variable = symbolTable.copyUp(variable); + symbol = symbolTable.copyUp(symbol)->getAsVariable(); } // Now, modify the type of the copy, as per the type of the current redeclaration. // TODO: functionality: verify type change is allowed and make the change in type - return variable; + return symbol; } return 0; @@ -2029,8 +2021,8 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier, // Check for redeclaration of built-ins and/or attempting to declare a reserved name bool newDeclaration = false; // true if a new entry gets added to the symbol table - TVariable* variable = redeclareBuiltin(loc, identifier, newDeclaration); - if (! variable) + TSymbol* symbol = redeclareBuiltin(loc, identifier, newDeclaration); + if (! symbol) reservedErrorCheck(loc, identifier); // Declare the variable @@ -2042,7 +2034,7 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier, arrayDimCheck(loc, &type, arraySizes); if (! arrayQualifierError(loc, type.getQualifier())) { type.setArraySizes(arraySizes); - declareArray(loc, identifier, type, variable, newDeclaration); + declareArray(loc, identifier, type, symbol, newDeclaration); } if (initializer) { @@ -2051,18 +2043,24 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier, } } else { // non-array case - if (! variable) - variable = declareNonArray(loc, identifier, type, newDeclaration); + if (! symbol) + symbol = declareNonArray(loc, identifier, type, newDeclaration); } // Deal with initializer TIntermNode* initNode = 0; - if (variable && initializer) + if (symbol && initializer) { + TVariable* variable = symbol->getAsVariable(); + if (! variable) { + error(loc, "initializer requires a variable, not a member", identifier.c_str(), ""); + return 0; + } initNode = executeInitializer(loc, identifier, initializer, variable); + } // see if it's a linker-level object to track - if (newDeclaration && symbolTable.atGlobalLevel()) - intermediate.addSymbolLinkageNode(linkage, *variable); + if (symbol && newDeclaration && symbolTable.atGlobalLevel()) + intermediate.addSymbolLinkageNode(linkage, *symbol); return initNode; } @@ -2435,11 +2433,13 @@ void TParseContext::addBlock(TSourceLoc loc, TTypeList& typeList, const TString* // For an identifier that is already declared, add more qualification to it. void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, const TString& identifier) { - TSymbol* existing = symbolTable.find(identifier); - TVariable* variable = existing ? existing->getAsVariable() : 0; - if (! variable) { + TSymbol* symbol = symbolTable.find(identifier); + if (! symbol) { error(loc, "identifier not previously declared", identifier.c_str(), ""); - + return; + } + if (symbol->getAsFunction()) { + error(loc, "cannot re-qualify a function name", identifier.c_str(), ""); return; } @@ -2453,12 +2453,13 @@ void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, return; } - // For read-only built-ins, add a new variable for holding the modified qualifier. - if (variable->isReadOnly()) - variable = symbolTable.copyUp(variable); + // For read-only built-ins, add a new symbol for holding the modified qualifier. + // This will bring up an entire block, if a block type has to be modified (e.g., gl_Position inside a block) + if (symbol->isReadOnly()) + symbol = symbolTable.copyUp(symbol); if (qualifier.invariant) - variable->getWritableType().getQualifier().invariant = true; + symbol->getWritableType().getQualifier().invariant = true; } void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, TIdentifierList& identifiers) diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index fdfe1486..37dac2aa 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -111,7 +111,7 @@ public: void precisionQualifierCheck(TSourceLoc, TPublicType&); void parameterSamplerCheck(TSourceLoc, TStorageQualifier qualifier, const TType& type); bool containsSampler(const TType& type); - TVariable* redeclareBuiltin(TSourceLoc, const TString&, bool& newDeclaration); + TSymbol* redeclareBuiltin(TSourceLoc, const TString&, bool& newDeclaration); void paramCheck(TSourceLoc, TStorageQualifier qualifier, TType* type); void nestedBlockCheck(TSourceLoc); void nestedStructCheck(TSourceLoc); @@ -139,7 +139,7 @@ public: TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc); TIntermTyped* addConstStruct(TString& , TIntermTyped*, TSourceLoc); - bool arraySetMaxSize(TSourceLoc, TIntermSymbol*, int); + void updateMaxArraySize(TSourceLoc, TIntermNode*, int index); void setScanContext(TScanContext* c) { scanContext = c; } TScanContext* getScanContext() const { return scanContext; } @@ -164,7 +164,7 @@ protected: const char* getPreamble(); void nonInitConstCheck(TSourceLoc, TString& identifier, TType& type); TVariable* declareNonArray(TSourceLoc, TString& identifier, TType&, bool& newDeclaration); - void declareArray(TSourceLoc, TString& identifier, const TType&, TVariable*&, bool& newDeclaration); + void declareArray(TSourceLoc, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration); TIntermNode* executeInitializer(TSourceLoc, TString& identifier, TIntermTyped* initializer, TVariable* variable); TOperator mapTypeToConstructorOp(const TType&); diff --git a/glslang/MachineIndependent/SymbolTable.cpp b/glslang/MachineIndependent/SymbolTable.cpp index 67fccaec..2977a2e5 100644 --- a/glslang/MachineIndependent/SymbolTable.cpp +++ b/glslang/MachineIndependent/SymbolTable.cpp @@ -240,7 +240,7 @@ TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf) } } -TVariable* TVariable::clone() +TVariable* TVariable::clone() const { TVariable *variable = new TVariable(*this); @@ -261,28 +261,45 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf) defined = copyOf.defined; } -TFunction* TFunction::clone() +TFunction* TFunction::clone() const { TFunction *function = new TFunction(*this); return function; } -TAnonMember* TAnonMember::clone() +TAnonMember* TAnonMember::clone() const { - // need to implement this once built-in symbols include interface blocks + // Anonymous members of a given block should be cloned at a higher level, + // where they can all be assured to still end up pointing to a single + // copy of the original container. assert(0); return 0; } -TSymbolTableLevel* TSymbolTableLevel::clone() +TSymbolTableLevel* TSymbolTableLevel::clone() const { TSymbolTableLevel *symTableLevel = new TSymbolTableLevel(); symTableLevel->anonId = anonId; - tLevel::iterator iter; - for (iter = level.begin(); iter != level.end(); ++iter) - symTableLevel->insert(*iter->second->clone()); + std::vector containerCopied(anonId, false); + tLevel::const_iterator iter; + for (iter = level.begin(); iter != level.end(); ++iter) { + const TAnonMember* anon = iter->second->getAsAnonMember(); + if (anon) { + // Insert all the anonymous members of this same container at once, + // avoid inserting the other members in the future, once this has been done, + // allowing them to all be part of the same new container. + if (! containerCopied[anon->getAnonId()]) { + TVariable* container = anon->getAnonContainer().clone(); + container->changeName(NewPoolTString("")); + // insert the whole container + symTableLevel->insert(*container); + containerCopied[anon->getAnonId()] = true; + } + } else + symTableLevel->insert(*iter->second->clone()); + } return symTableLevel; } diff --git a/glslang/MachineIndependent/SymbolTable.h b/glslang/MachineIndependent/SymbolTable.h index a0db1957..0758a1cc 100644 --- a/glslang/MachineIndependent/SymbolTable.h +++ b/glslang/MachineIndependent/SymbolTable.h @@ -45,8 +45,7 @@ // symbols. // // --> This requires a copy mechanism, so initial pools used to create -// the shared information can be popped. So, care is taken with -// copying pointers to point to new copies. Done through "clone" +// the shared information can be popped. Done through "clone" // methods. // // * Name mangling will be used to give each function a unique name @@ -74,30 +73,34 @@ namespace glslang { // // Symbol base class. (Can build functions or variables out of these...) // + class TVariable; class TFunction; class TAnonMember; + class TSymbol { public: POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) explicit TSymbol(const TString *n) : name(n), writable(true) { } - virtual TSymbol* clone() = 0; + virtual TSymbol* clone() const = 0; virtual ~TSymbol() { } - const TString& getName() const { return *name; } - void changeName(const TString* newName) { name = newName; } + virtual const TString& getName() const { return *name; } + virtual void changeName(const TString* newName) { name = newName; } virtual const TString& getMangledName() const { return getName(); } virtual TFunction* getAsFunction() { return 0; } virtual const TFunction* getAsFunction() const { return 0; } virtual TVariable* getAsVariable() { return 0; } virtual const TVariable* getAsVariable() const { return 0; } virtual const TAnonMember* getAsAnonMember() const { return 0; } - void setUniqueId(int id) { uniqueId = id; } - int getUniqueId() const { return uniqueId; } + virtual const TType& getType() const = 0; + virtual TType& getWritableType() = 0; + virtual void setUniqueId(int id) { uniqueId = id; } + virtual int getUniqueId() const { return uniqueId; } virtual void dump(TInfoSink &infoSink) const = 0; - bool isReadOnly() { return ! writable; } - void makeReadOnly() { writable = false; } + virtual bool isReadOnly() { return ! writable; } + virtual void makeReadOnly() { writable = false; } protected: explicit TSymbol(const TSymbol&); @@ -126,20 +129,19 @@ protected: class TVariable : public TSymbol { public: TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), userType(uT) { type.shallowCopy(t); } - virtual TVariable* clone(); + virtual TVariable* clone() const; virtual ~TVariable() { } virtual TVariable* getAsVariable() { return this; } virtual const TVariable* getAsVariable() const { return this; } - TType& getWritableType() { assert(writable); return type; } - const TType& getType() const { return type; } - bool isUserType() const { return userType; } + virtual const TType& getType() const { return type; } + virtual TType& getWritableType() { assert(writable); return type; } + virtual bool isUserType() const { return userType; } + virtual const TConstUnionArray& getConstArray() const { return unionArray; } + virtual void setConstArray(const TConstUnionArray& constArray) { unionArray = constArray; } virtual void dump(TInfoSink &infoSink) const; - const TConstUnionArray& getConstArray() const { return unionArray; } - void setConstArray(const TConstUnionArray& constArray) { unionArray = constArray; } - protected: explicit TVariable(const TVariable&); TVariable& operator=(const TVariable&); @@ -182,35 +184,36 @@ public: mangledName(*name + '('), op(tOp), defined(false) { returnType.shallowCopy(retType); } - virtual TFunction* clone(); + virtual TFunction* clone() const; virtual ~TFunction(); virtual TFunction* getAsFunction() { return this; } virtual const TFunction* getAsFunction() const { return this; } - void addParameter(TParameter& p) + virtual void addParameter(TParameter& p) { assert(writable); parameters.push_back(p); p.type->appendMangledName(mangledName); } - const TString& getMangledName() const { return mangledName; } - const TType& getReturnType() const { return returnType; } - void relateToOperator(TOperator o) { assert(writable); op = o; } - TOperator getBuiltInOp() const { return op; } - void setDefined() { assert(writable); defined = true; } - bool isDefined() const { return defined; } + virtual const TString& getMangledName() const { return mangledName; } + virtual const TType& getType() const { return returnType; } + virtual TType& getWritableType() { return returnType; } + virtual void relateToOperator(TOperator o) { assert(writable); op = o; } + virtual TOperator getBuiltInOp() const { return op; } + virtual void setDefined() { assert(writable); defined = true; } + virtual bool isDefined() const { return defined; } - int getParamCount() const { return static_cast(parameters.size()); } - TParameter& operator [](int i) { assert(writable); return parameters[i]; } - const TParameter& operator [](int i) const { return parameters[i]; } + virtual int getParamCount() const { return static_cast(parameters.size()); } + virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; } + virtual const TParameter& operator[](int i) const { return parameters[i]; } virtual void dump(TInfoSink &infoSink) const; protected: explicit TFunction(const TFunction&); - TFunction& operator=(TFunction&); + TFunction& operator=(const TFunction&); typedef TVector TParamList; TParamList parameters; @@ -222,21 +225,37 @@ protected: class TAnonMember : public TSymbol { public: - TAnonMember(const TString* n, unsigned int m, TSymbol& a) : TSymbol(n), anonContainer(a), memberNumber(m) { } - virtual TAnonMember* clone(); + TAnonMember(const TString* n, unsigned int m, const TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { } + virtual TAnonMember* clone() const; virtual ~TAnonMember() { } - const TAnonMember* getAsAnonMember() const { return this; } - TSymbol& getAnonContainer() const { return anonContainer; } - unsigned int getMemberNumber() const { return memberNumber; } + virtual const TAnonMember* getAsAnonMember() const { return this; } + virtual const TVariable& getAnonContainer() const { return anonContainer; } + virtual unsigned int getMemberNumber() const { return memberNumber; } + + virtual const TType& getType() const + { + TTypeList& types = *anonContainer.getType().getStruct(); + return *types[memberNumber].type; + } + + virtual TType& getWritableType() + { + assert(writable); + TTypeList& types = *anonContainer.getType().getStruct(); + return *types[memberNumber].type; + } + + virtual int getAnonId() const { return anonId; } virtual void dump(TInfoSink &infoSink) const; protected: - explicit TAnonMember(TAnonMember&); - TAnonMember& operator=(TAnonMember&); + explicit TAnonMember(const TAnonMember&); + TAnonMember& operator=(const TAnonMember&); - TSymbol& anonContainer; + const TVariable& anonContainer; unsigned int memberNumber; + int anonId; }; class TSymbolTableLevel { @@ -256,18 +275,20 @@ public: // An empty name means an anonymous container, exposing its members to the external scope. // Give it a name and insert its members in the symbol table, pointing to the container. char buf[20]; - snprintf(buf, 20, "__anon__%d", anonId++); + snprintf(buf, 20, "__anon__%d", anonId); symbol.changeName(NewPoolTString(buf)); bool isOkay = true; const TTypeList& types = *symbol.getAsVariable()->getType().getStruct(); for (unsigned int m = 0; m < types.size(); ++m) { - TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, symbol); + TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, *symbol.getAsVariable(), anonId); result = level.insert(tLevelPair(member->getMangledName(), member)); if (! result.second) isOkay = false; } + ++anonId; + return isOkay; } else { // Check for redefinition errors: @@ -344,7 +365,7 @@ public: void relateToOperator(const char* name, TOperator op); void dump(TInfoSink &infoSink) const; - TSymbolTableLevel* clone(); + TSymbolTableLevel* clone() const; void readOnly(); protected: @@ -422,7 +443,7 @@ public: { symbol.setUniqueId(++uniqueId); - if (symbol.getAsVariable()) { + if (! symbol.getAsFunction()) { // make sure there isn't a function of this name if (table[currentLevel()]->hasFunctionName(symbol.getName())) return false; @@ -438,16 +459,27 @@ public: } // - // 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. + // Copy a variable or anonymous member's structure 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(); - variable->setUniqueId(shared->getUniqueId()); - table[currentLevel()]->insert(*variable); - - return variable; + TSymbol* copyUp(TSymbol* shared) + { + TSymbol* copy; + if (shared->getAsVariable()) { + copy = shared->clone(); + copy->setUniqueId(shared->getUniqueId()); + table[currentLevel()]->insert(*copy); + return copy; + } else { + const TAnonMember* anon = shared->getAsAnonMember(); + assert(anon); + TVariable* container = anon->getAnonContainer().clone(); + container->changeName(NewPoolTString("")); + container->setUniqueId(anon->getAnonContainer().getUniqueId()); + table[currentLevel()]->insert(*container); + return table[currentLevel()]->find(shared->getName()); + } } TSymbol* find(const TString& name, bool* builtIn = 0, bool *currentScope = 0) diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index d89b937d..460742d2 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -2378,7 +2378,7 @@ function_definition parseContext.error($1.loc, "function does not return a value:", "", $1.function->getName().c_str()); parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); $$ = parseContext.intermediate.growAggregate($1.intermAggregate, $3); - parseContext.intermediate.setAggregateOperator($$, EOpFunction, $1.function->getReturnType(), $1.loc); + parseContext.intermediate.setAggregateOperator($$, EOpFunction, $1.function->getType(), $1.loc); $$->getAsAggregate()->setName($1.function->getMangledName().c_str()); // store the pragma information for debug and optimize and other vendor specific diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index 1705d464..b8c37274 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -49,7 +49,7 @@ struct TVectorFields { }; class TSymbolTable; -class TVariable; +class TSymbol; // // Set of helper functions to help parse and build the tree. @@ -97,7 +97,7 @@ public: bool postProcess(TIntermNode*, EShLanguage); void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&); void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&); - void addSymbolLinkageNode(TIntermAggregate*& linkage, const TVariable&); + void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&); void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee); void merge(TInfoSink&, TIntermediate&);