Restore r26192, r26240, r26241:  All three about implicit-array sizing design and implementation.  *Minus* test results.

r26192: Link-time sizing of implicitly-sized arrays and handling of anonymous blocks containing implicitly-sized members.  Also changed "__anon" to "anon@" and encapsulated it.

r26240: Solidify the sharing of struct and array information between nodes and variables: A single copy now allows for simultaneously setting array size for all effected nodes and symbols of a given type. This allowed removal of ioArrayNodeResizeList and makes nodes of implicitly sized arrays know the final size.

r26241: Fix g++ issue with wanting non-const iterator.


git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@26218 e7fa87d3-cd2b-0410-9028-fcbf551c1848
diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h
index 0b3917c..e4c84dc 100644
--- a/glslang/Include/Types.h
+++ b/glslang/Include/Types.h
@@ -44,6 +44,12 @@
 
 const int GlslangMaxTypeLength = 200;  // TODO: need to print block/struct one member per line, so this can stay bounded
 
+const char* const AnonymousPrefix = "anon@"; // for something like a block whose members can be directly accessed
+inline bool IsAnonymous(const TString& name)
+{
+    return name.compare(0, 5, AnonymousPrefix) == 0;
+}
+
 //
 // Details within a sampler type
 //
@@ -174,7 +180,7 @@
 struct TArraySizes {
     POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
 
-    TArraySizes() : implicitArraySize(0) { }
+    TArraySizes() : implicitArraySize(1) { }
     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; }
@@ -701,14 +707,14 @@
                                     sampler.clear();
                                 qualifier = p.qualifier;
                                 if (p.userDef) {
-                                    structure = p.userDef->getStruct();
+                                    structure = p.userDef->getWritableStruct();  // public type is short-lived; there are no sharing issues
                                     typeName = NewPoolTString(p.userDef->getTypeName().c_str());
                                 }
                             }
     // to efficiently make a dereferenced type
     // without ever duplicating the outer structure that will be thrown away
     // and using only shallow copy
-    TType(const TType& type, int derefIndex)
+    TType(const TType& type, int derefIndex, bool rowMajor = false)
                             {
                                 if (! type.isArray() && (type.basicType == EbtStruct || type.basicType == EbtBlock)) {
                                     // do a structure dereference
@@ -718,7 +724,7 @@
                                 } else {
                                     // do an array/vector/matrix dereference
                                     shallowCopy(type);
-                                    dereference();
+                                    dereference(rowMajor);
                                 }
                             }
     // for making structures, ...
@@ -761,12 +767,12 @@
     {
         shallowCopy(copyOf);
 
-        if (arraySizes) {
+        if (copyOf.arraySizes) {
             arraySizes = new TArraySizes;
             *arraySizes = *copyOf.arraySizes;
         }
 
-        if (structure) {
+        if (copyOf.structure) {
             structure = new TTypeList;
             TStructureMapIterator iter;
             for (unsigned int i = 0; i < copyOf.structure->size(); ++i) {
@@ -778,9 +784,9 @@
             }
         }
 
-        if (fieldName)
+        if (copyOf.fieldName)
             fieldName = NewPoolTString(copyOf.fieldName->c_str());
-        if (typeName)
+        if (copyOf.typeName)
             typeName = NewPoolTString(copyOf.typeName->c_str());
     }
     
@@ -793,47 +799,48 @@
     }
 
     // Merge type from parent, where a parentType is at the beginning of a declaration,
-    // establishing some charastics for all subsequent names, while this type
+    // establishing some characteristics for all subsequent names, while this type
     // is on the individual names.
     void mergeType(const TPublicType& parentType)
     {
         // arrayness is currently the only child aspect that has to be preserved
-        setElementType(parentType.basicType, parentType.vectorSize, parentType.matrixCols, parentType.matrixRows, parentType.userDef);
+        basicType = parentType.basicType;
+        vectorSize = parentType.vectorSize;
+        matrixCols = parentType.matrixCols;
+        matrixRows = parentType.matrixRows;
         qualifier = parentType.qualifier;
         sampler = parentType.sampler;
         if (parentType.arraySizes)
             setArraySizes(parentType.arraySizes);
-        if (parentType.userDef)
+        if (parentType.userDef) {
+            structure = parentType.userDef->getWritableStruct();
             setTypeName(parentType.userDef->getTypeName());
+        }
     }
 
-    virtual void dereference()
+    virtual void dereference(bool rowMajor = false)
     {
         if (arraySizes)
             arraySizes = 0;
         else if (matrixCols > 0) {
-            vectorSize = matrixRows;
+            if (rowMajor)
+                vectorSize = matrixCols;
+            else
+                vectorSize = matrixRows;
             matrixCols = 0;
             matrixRows = 0;
         } else if (vectorSize > 1)
             vectorSize = 1;
     }
 
-    virtual void setElementType(TBasicType t, int s, int mc, int mr, const TType* userDef)
-    {
-        basicType = t;
-        vectorSize = s;
-        matrixCols = mc;
-        matrixRows = mr;
-        if (userDef)
-            structure = userDef->getStruct();
-        // leave array information intact.
-    }
+    virtual void hideType() { basicType = EbtVoid; vectorSize = 1; }
+    virtual bool wasTypeHidden() const { return basicType == EbtVoid; }
+
     virtual void setTypeName(const TString& n) { typeName = NewPoolTString(n.c_str()); }
     virtual void setFieldName(const TString& n) { fieldName = NewPoolTString(n.c_str()); }
     virtual const TString& getTypeName() const
     {
-        assert(typeName);    		
+        assert(typeName);
         return *typeName;
     }
 
@@ -845,17 +852,22 @@
 
     virtual TBasicType getBasicType() const { return basicType; }
     virtual const TSampler& getSampler() const { return sampler; }
-    virtual TQualifier& getQualifier() { return qualifier; }
+
+    virtual       TQualifier& getQualifier()       { return qualifier; }
     virtual const TQualifier& getQualifier() const { return qualifier; }
 
     virtual int getVectorSize() const { return vectorSize; }
     virtual int getMatrixCols() const { return matrixCols; }
     virtual int getMatrixRows() const { return matrixRows; }
+    virtual int getArraySize()  const { return arraySizes->sizes.front(); }
+    virtual int getImplicitArraySize () const { return arraySizes->implicitArraySize; }
 
     virtual bool isScalar() const { return vectorSize == 1 && ! isStruct() && ! isArray(); }
     virtual bool isVector() const { return vectorSize > 1; }
     virtual bool isMatrix() const { return matrixCols ? true : false; }
     virtual bool isArray()  const { return arraySizes != 0; }
+    virtual bool isImplicitlySizedArray() const { return isArray() && ! getArraySize(); }
+    virtual bool isExplicitlySizedArray() const { return ! isImplicitlySizedArray(); }
     virtual bool isStruct() const { return structure != 0; }
 
     // Recursively checks if the type contains the given basic type
@@ -885,28 +897,58 @@
         }
         return false;
     }
-    int getArraySize() const { return arraySizes->sizes.front(); }
-    void shareArraySizes(const TType& type)
+
+    // Recursively check the structure for any implicitly-sized arrays, needed for triggering a copyUp().
+    virtual bool containsImplicitlySizedArray() const
     {
-        // For when we are sharing existing array descriptors.
-        // This allows all references to the same array
-        // to be updated at once, by having all of them share the
-        // array description.
+        if (isImplicitlySizedArray())
+            return true;
+        if (! structure)
+            return false;
+        for (unsigned int i = 0; i < structure->size(); ++i) {
+            if ((*structure)[i].type->containsImplicitlySizedArray())
+                return true;
+        }
+        return false;
+    }
+
+    // Array editing methods.  Array descriptors can be shared across
+    // type instances.  This allows all uses of the same array
+    // to be updated at once.  E.g., all nodes can be explicitly sized
+    // by tracking and correcting one implicit size.  Or, all nodes
+    // can get the explicit size on a redeclaration that gives size.
+    //
+    // N.B.:  Don't share with the shared symbol tables (symbols are
+    // marked as isReadOnly().  Such symbols with arrays that will be
+    // edited need to copyUp() on first use, so that 
+    // A) the edits don't effect the shared symbol table, and
+    // B) the edits are shared across all users.
+    void updateArraySizes(const TType& type)
+    {
+        // For when we may already be sharing existing array descriptors,
+        // keeping the pointers the same, just updating the contents.
         *arraySizes = *type.arraySizes;
     }
     void setArraySizes(TArraySizes* s)
     {
-        // For when we don't want distinct types sharing the same descriptor.
+        // For setting a fresh new set of array sizes, not yet worrying about sharing.
         arraySizes = new TArraySizes;
         *arraySizes = *s;
     }
     void setArraySizes(const TType& type) { setArraySizes(type.arraySizes); }
-    
     void changeArraySize(int s) { arraySizes->sizes.front() = s; }
-    bool isImplicitlySizedArray() const { return isArray() && ! getArraySize(); }
-    bool isExplicitlySizedArray() const { return ! isImplicitlySizedArray(); }
     void setImplicitArraySize (int s) { arraySizes->implicitArraySize = s; }
-    int getImplicitArraySize () const { return arraySizes->implicitArraySize; }
+
+    // Recursively make the implicit array size the explicit array size, through the type tree.
+    void adoptImplicitArraySizes()
+    {
+        if (isImplicitlySizedArray())
+            changeArraySize(getImplicitArraySize());
+        if (isStruct()) {
+            for (int i = 0; i < (int)structure->size(); ++i)
+                (*structure)[i].type->adoptImplicitArraySizes();
+        }
+    }
 
     const char* getBasicString() const 
     {
@@ -1044,15 +1086,15 @@
 
     const char* getStorageQualifierString() const { return GetStorageQualifierString(qualifier.storage); }
     const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); }
-    TTypeList* getStruct() { return structure; }
-    TTypeList* getStruct() const { return structure; }
+    const TTypeList* getStruct() const { return structure; }
+    TTypeList* getWritableStruct() const { return structure; }  // This should only be used when known to not be sharing with other threads
 
     int computeNumComponents() const
     {
         int components = 0;
 
         if (getBasicType() == EbtStruct || getBasicType() == EbtBlock) {
-            for (TTypeList::iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
+            for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
                 components += ((*tl).type)->computeNumComponents();
         } else if (matrixCols)
             components = matrixCols * matrixRows;
@@ -1158,9 +1200,8 @@
     TSampler sampler;
     TQualifier qualifier;
 
-    TArraySizes* arraySizes;
-
-    TTypeList* structure;       // 0 unless this is a struct
+    TArraySizes* arraySizes;    // 0 unless this is an array; can be shared across types
+    TTypeList* structure;       // 0 unless this is a struct; can be shared across types
     TString *fieldName;         // for structure field names
     TString *typeName;          // for structure type name
 };
diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp
index 5195a0b..62ff0c5 100644
--- a/glslang/MachineIndependent/Intermediate.cpp
+++ b/glslang/MachineIndependent/Intermediate.cpp
@@ -866,10 +866,10 @@
     // by the AST.
     //
     // Almost entirely, translation of symbols is driven by what's present 
-    // in the AST traversal, not by translating the symbol table.  
+    // in the AST traversal, not by translating the symbol table.
     //
     // However, there are some special cases:
-    //  - From the specification: "Special built-in inputs gl_VertexID and 
+    //  - From the specification: "Special built-in inputs gl_VertexID and
     //    gl_InstanceID are also considered active vertex attributes."
     //  - Linker-based type mismatch error reporting needs to see all 
     //    uniforms/ins/outs variables and blocks.
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 8b2be3c..3fcdbaf 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -371,59 +371,56 @@
 TIntermTyped* TParseContext::handleVariable(TSourceLoc loc, TSymbol* symbol, TString* string)
 {
     TIntermTyped* node = 0;
-    bool noteAccess = false;
 
     // Error check for function requiring specific extensions present.
     if (symbol && symbol->getNumExtensions())
         requireExtensions(loc, symbol->getNumExtensions(), symbol->getExtensions(), symbol->getName().c_str());
 
+    if (symbol && symbol->isReadOnly()) {
+        // All shared things containing an implicitly sized array must be copied up 
+        // on first use, so that all future references will share its array structure,
+        // so that editing the implicit size will effect all nodes consuming it,
+        // and so that editing the implicit size won't change the shared one.
+        if (symbol->getType().containsImplicitlySizedArray())
+            makeEditable(symbol);
+    }
+
+    const TVariable* variable;
     const TAnonMember* anon = symbol ? symbol->getAsAnonMember() : 0;
     if (anon) {
-        // it was a member of an anonymous container
-        
-        // create a subtree for its dereference
-        const TVariable* variable = anon->getAnonContainer().getAsVariable();
+        // It was a member of an anonymous container.
+
+        // Create a subtree for its dereference.
+        variable = anon->getAnonContainer().getAsVariable();
         TIntermTyped* container = intermediate.addSymbol(*variable, loc);
         TConstUnionArray unionArray(1);
         unionArray[0].setUConst(anon->getMemberNumber());
         TIntermTyped* constNode = intermediate.addConstantUnion(unionArray, TType(EbtUint, EvqConst), loc);
-
         node = intermediate.addIndex(EOpIndexDirectStruct, container, constNode, loc);
-        node->setType(*(*variable->getType().getStruct())[anon->getMemberNumber()].type);
-        if (node->getBasicType() == EbtVoid)
-            error(loc, "member of nameless block was not redeclared", string->c_str(), "");
-        if (variable->getType().getQualifier().isIo())
-            noteAccess = true;
 
-        // TODO: does this create any accidental type sharing with the built-in level?
+        node->setType(*(*variable->getType().getStruct())[anon->getMemberNumber()].type);
+        if (node->getType().wasTypeHidden())
+            error(loc, "member of nameless block was not redeclared", string->c_str(), "");
     } else {
-        // The symbol table search was done in the lexical phase, but
-        // if this is a new symbol, it wouldn't have found it.
-        TVariable* variable = symbol ? symbol->getAsVariable() : 0;
+        // Not a member of an anonymous container.
+
+        // The symbol table search was done in the lexical phase.
+        // See if it was a variable.
+        variable = symbol ? symbol->getAsVariable() : 0;
         if (symbol && ! variable)
             error(loc, "variable name expected", string->c_str(), "");
 
+        // Recovery, if it wasn't found or was not a variable.
         if (! variable)
             variable = new TVariable(string, TType(EbtVoid));
 
         if (variable->getType().getQualifier().storage == EvqConst)
             node = intermediate.addConstantUnion(variable->getConstArray(), variable->getType(), loc);
-        else {
-            TType* type;
-            if (variable->isReadOnly()) {
-                type = new TType;
-                // break type sharing with built-ins; only costs if there are arrays or structures
-                type->deepCopy(variable->getType());
-            } else
-                type = &variable->getWritableType();
-            // addSymbol will do a shallow copy of the type to the node, thus sharing array and struct information
-            node = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), *type, loc);
-            if (type->getQualifier().isIo())
-                noteAccess = true;
-        }
+        else
+            node = intermediate.addSymbol(*variable, loc);
     }
 
-    if (noteAccess)
+    if (variable->getType().getQualifier().isIo())
         intermediate.addIoAccessed(*string);
 
     return node;
@@ -543,6 +540,22 @@
     }
 }
 
+// Make a shared symbol have a non-shared version that can be edited by the current 
+// compile, such that editing its type will not change the shared version and will
+// effect all nodes sharing it.
+void TParseContext::makeEditable(TSymbol*& symbol)
+{
+    // copyUp() does a deep copy of the type.
+    symbol = symbolTable.copyUp(symbol);
+
+    // Also, see if it's tied to IO resizing
+    if (isIoResizeArray(symbol->getType()))
+        ioArraySymbolResizeList.push_back(symbol);
+
+    // Also, save it in the AST for linker use.
+    intermediate.addSymbolLinkageNode(linkage, *symbol);
+}
+
 // Return true if this is a geometry shader input array or tessellation control output array.
 bool TParseContext::isIoResizeArray(const TType& type) const
 {
@@ -585,33 +598,20 @@
 }
 
 // Handle a dereference of a geometry shader input array or tessellation control output array.
-// See ioArrayNodeResizeList comment in ParseHelper.h.
+// See ioArraySymbolResizeList comment in ParseHelper.h.
 //
 void TParseContext::handleIoResizeArrayAccess(TSourceLoc loc, TIntermTyped* base)
 {
-    TIntermSymbol* symbol = base->getAsSymbolNode();
-    assert(symbol);
-    ioArrayNodeResizeList.push_back(symbol);
-    if (symbol && builtInName(symbol->getName())) {
-        // make sure we have a user-modifiable copy of this built-in input array
-        TSymbol* arry = symbolTable.find(symbol->getName());
-        if (arry->isReadOnly()) {
-            arry = symbolTable.copyUp(arry);
+    TIntermSymbol* symbolNode = base->getAsSymbolNode();
+    assert(symbolNode);
+    if (! symbolNode)
+        return;
 
-            // fix array size, if already implicitly size
-            if (arry->getType().isImplicitlySizedArray()) {
-                int newSize = getIoArrayImplicitSize();
-                if (newSize) {
-                    arry->getWritableType().changeArraySize(newSize);
-                    symbol->getWritableType().changeArraySize(newSize);
-                }
-            }
-
-            ioArraySymbolResizeList.push_back(arry);
-
-            // Save it in the AST for linker use.
-            intermediate.addSymbolLinkageNode(linkage, *arry);
-        }
+    // fix array size, if it can be fixed and needs to be fixed (will allow variable indexing)
+    if (symbolNode->getType().isImplicitlySizedArray()) {
+        int newSize = getIoArrayImplicitSize();
+        if (newSize)
+            symbolNode->getWritableType().changeArraySize(newSize);
     }
 }
 
@@ -640,9 +640,6 @@
         return;
     }
 
-    for (size_t i = 0; i < ioArrayNodeResizeList.size(); ++i)
-        checkIoArrayConsistency(loc, requiredSize, feature, ioArrayNodeResizeList[i]->getWritableType(), ioArrayNodeResizeList[i]->getName());
-
     for (size_t i = 0; i < ioArraySymbolResizeList.size(); ++i)
         checkIoArrayConsistency(loc, requiredSize, feature, ioArraySymbolResizeList[i]->getWritableType(), ioArraySymbolResizeList[i]->getName());
 }
@@ -732,7 +729,7 @@
     } else if (base->isMatrix())
         error(loc, "field selection not allowed on matrix", ".", "");
     else if (base->getBasicType() == EbtStruct || base->getBasicType() == EbtBlock) {
-        TTypeList* fields = base->getType().getStruct();
+        const TTypeList* fields = base->getType().getStruct();
         bool fieldFound = false;
         unsigned int member;
         for (member = 0; member < fields->size(); ++member) {
@@ -2118,7 +2115,7 @@
         return true;
 
     if (type.getBasicType() == EbtStruct) {
-        TTypeList& structure = *type.getStruct();
+        const TTypeList& structure = *type.getStruct();
         for (unsigned int i = 0; i < structure.size(); ++i) {
             if (containsSampler(*structure[i].type))
                 return true;
@@ -2204,7 +2201,7 @@
 }
 
 //
-// Do all the semantic checking for declaring an array, with and
+// Do all the semantic checking for declaring or redeclaring an array, with and
 // without a size, and make the right changes to the symbol table.
 //
 // size == 0 means no specified size.
@@ -2249,27 +2246,28 @@
         return;
     }
 
-    TType& newType = symbol->getWritableType();
+    // redeclareBuiltinVariable() should have already done the copyUp()
+    TType& existingType = symbol->getWritableType();
 
-    if (! newType.isArray()) {
+    if (! existingType.isArray()) {
         error(loc, "redeclaring non-array as array", identifier.c_str(), "");
         return;
     }
-    if (newType.isExplicitlySizedArray()) {
+    if (existingType.isExplicitlySizedArray()) {
         // be more leniant for input arrays to geometry shaders and tessellation control outputs, where the redeclaration is the same size
-        if (! (isIoResizeArray(type) && newType.getArraySize() == type.getArraySize()))
+        if (! (isIoResizeArray(type) && existingType.getArraySize() == type.getArraySize()))
             error(loc, "redeclaration of array with size", identifier.c_str(), "");
         return;
     }
 
-    if (! newType.sameElementType(type)) {
+    if (! existingType.sameElementType(type)) {
         error(loc, "redeclaration of array with a different type", identifier.c_str(), "");
         return;
     }
 
     arrayLimitCheck(loc, identifier, type.getArraySize());
 
-    newType.shareArraySizes(type);
+    existingType.updateArraySizes(type);
 
     if (isIoResizeArray(type))
         checkIoArraysConsistency(loc);
@@ -2284,13 +2282,29 @@
 
     // something to do...
 
-    // TODO: 1.50 linker: unsized block member array: 'node' could be an expression for a dereference
-    TIntermSymbol* symbolNode = node->getAsSymbolNode();
-    if (! symbolNode)
-        return;
+    // Figure out what symbol to lookup, as we will use its type to edit for the size change,
+    // as that type will be shared through shallow copies for future references.
+    TSymbol* symbol = 0;
+    int blockIndex = -1;
+    const TString* lookupName;
+    if (node->getAsSymbolNode())
+        lookupName = &node->getAsSymbolNode()->getName();
+    else if (node->getAsBinaryNode()) {
+        const TIntermBinary* deref = node->getAsBinaryNode();
+        // This has to be the result of a block dereference, unless it's bad shader code
+        if (! deref->getLeft()->getAsSymbolNode() || deref->getLeft()->getBasicType() != EbtBlock ||
+            deref->getRight()->getAsConstantUnion() == 0)
+            return;
 
-    TSymbol* symbol = symbolTable.find(symbolNode->getName());
-    assert(symbol);
+        blockIndex = deref->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
+
+        lookupName = &deref->getLeft()->getAsSymbolNode()->getName();
+        if (IsAnonymous(*lookupName))
+            lookupName = &(*deref->getLeft()->getType().getStruct())[blockIndex].type->getFieldName();
+    }
+
+    // Lookup the symbol, should only fail if shader code is incorrect
+    symbol = symbolTable.find(*lookupName);
     if (symbol == 0)
         return;
 
@@ -2299,18 +2313,6 @@
         return;
     }
 
-    // For read-only built-ins, add a new variable for holding the maximum array size of an implicitly-sized shared array.
-    // TODO: desktop linker: unsized arrays: is this new array type shared with the node?
-    if (symbol->isReadOnly()) {
-        symbol = symbolTable.copyUp(symbol);
-        
-        if (isIoResizeArray(symbol->getType()))
-            ioArraySymbolResizeList.push_back(symbol);
-
-        // Save it in the AST for linker use.
-        intermediate.addSymbolLinkageNode(linkage, *symbol);
-    }
-
     symbol->getWritableType().setImplicitArraySize(index + 1);
 }
 
@@ -2371,14 +2373,8 @@
         // redeclaration.  Otherwise, make the new one.
         if (builtIn) {
             // Copy the symbol up to make a writable version
+            makeEditable(symbol);
             newDeclaration = true;
-            symbol = symbolTable.copyUp(symbol);
-
-            if (isIoResizeArray(symbol->getType()))
-                ioArraySymbolResizeList.push_back(symbol);
-
-            // Save it in the AST for linker use.
-            intermediate.addSymbolLinkageNode(linkage, *symbol);
         }
 
         // Now, modify the type of the copy, as per the type of the current redeclaration.
@@ -2490,12 +2486,12 @@
     //  - remove unused members
     //  - ensure remaining qualifiers/types match
     TType& type = block->getWritableType();
-    TTypeList::iterator member = type.getStruct()->begin();
+    TTypeList::iterator member = type.getWritableStruct()->begin();
     size_t numOriginalMembersFound = 0;
     while (member != type.getStruct()->end()) {
         // look for match
         bool found = false;
-        TTypeList::iterator newMember;
+        TTypeList::const_iterator newMember;
         TSourceLoc memberLoc;
         for (newMember = newTypeList.begin(); newMember != newTypeList.end(); ++newMember) {
             if (member->type->getFieldName() == newMember->type->getFieldName()) {
@@ -2536,13 +2532,13 @@
             // go to next member
             ++member;
         } else {    
-            // Use EbtVoid to tag missing members of anonymous blocks that have been redeclared,
-            // to hide the original (shared) declaration.
-            // (Instance-named blocks can just have the member removed.)
+            // For missing members of anonymous blocks that have been redeclared,
+            // hide the original (shared) declaration.
+            // Instance-named blocks can just have the member removed.
             if (instanceName)
-                member = type.getStruct()->erase(member);
+                member = type.getWritableStruct()->erase(member);
             else {
-                member->type->setElementType(EbtVoid, 1, 0, 0, 0);
+                member->type->hideType();
                 ++member;
             }
         }
@@ -2643,7 +2639,7 @@
 
 void TParseContext::structTypeCheck(TSourceLoc loc, TPublicType& publicType)
 {
-    TTypeList& typeList = *publicType.userDef->getStruct();
+    const TTypeList& typeList = *publicType.userDef->getStruct();
 
     // fix and check for member storage qualifiers and types that don't belong within a structure
     for (unsigned int member = 0; member < typeList.size(); ++member) {
@@ -3797,7 +3793,7 @@
 
     TIntermAggregate* aggrNode = node->getAsAggregate();
 
-    TTypeList::iterator memberTypes;
+    TTypeList::const_iterator memberTypes;
     if (op == EOpConstructStruct)
         memberTypes = type.getStruct()->begin();
 
diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp
index d781083..fc200a6 100644
--- a/glslang/MachineIndependent/ShaderLang.cpp
+++ b/glslang/MachineIndependent/ShaderLang.cpp
@@ -1064,7 +1064,7 @@
     intermediate[stage]->finalCheck(*infoSink);
 
     if (messages & EShMsgAST)
-        intermediate[stage]->output(*infoSink, stages[stage].size() > 1);
+        intermediate[stage]->output(*infoSink, true);
 
     return intermediate[stage]->getNumErrors() == 0;
 }
diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp
index 4a7d0bc..5c262bd 100644
--- a/glslang/MachineIndependent/linkValidate.cpp
+++ b/glslang/MachineIndependent/linkValidate.cpp
@@ -206,7 +206,10 @@
                 // Similarly for binding

                 if (! symbol->getQualifier().hasBinding() && unitSymbol->getQualifier().hasBinding())

                     symbol->getQualifier().layoutBinding = unitSymbol->getQualifier().layoutBinding;

-                

+

+                // Update implicit array sizes

+                mergeImplicitArraySizes(symbol->getWritableType(), unitSymbol->getType());

+

                 // Check for consistent types/qualification/initializers etc.

                 mergeErrorCheck(infoSink, *symbol, *unitSymbol, false);

             }

@@ -216,6 +219,25 @@
     }

 }

 

+// Recursively merge the implicit array sizes through the objects' respective type trees.

+void TIntermediate::mergeImplicitArraySizes(TType& type, const TType& unitType)

+{

+    if (type.isImplicitlySizedArray() && unitType.isArray()) {

+        int newImplicitArraySize = unitType.getArraySize();

+        if (newImplicitArraySize == 0)

+            newImplicitArraySize = unitType.getImplicitArraySize();

+        if (newImplicitArraySize > type.getImplicitArraySize ())

+            type.setImplicitArraySize(newImplicitArraySize);

+    }

+

+    // Type mismatches are caught and reported after this, just be careful for now.

+    if (! type.isStruct() || ! unitType.isStruct() || type.getStruct()->size() != unitType.getStruct()->size())

+        return;

+

+    for (int i = 0; i < (int)type.getStruct()->size(); ++i)

+        mergeImplicitArraySizes(*(*type.getStruct())[i].type, *(*unitType.getStruct())[i].type);

+}

+

 //

 // Compare two global objects from two compilation units and see if they match

 // well enough.  Rules can be different for intra- vs. cross-stage matching.

@@ -305,7 +327,7 @@
 // Do final link-time error checking of a complete (merged) intermediate representation.

 // (Much error checking was done during merging).

 //

-// Also, lock in defaults of things not set.

+// Also, lock in defaults of things not set, including array sizes.

 //

 void TIntermediate::finalCheck(TInfoSink& infoSink)

 {   

@@ -392,6 +414,21 @@
     case EShLangCompute:

         break;

     }

+

+    // Process the tree for any node-specific work.

+    class TFinalLinkTraverser : public TIntermTraverser {

+    public:

+        TFinalLinkTraverser() { }

+        virtual ~TFinalLinkTraverser() { }

+

+        virtual void visitSymbol(TIntermSymbol* symbol)

+        {

+            // Implicitly size arrays.

+            symbol->getWritableType().adoptImplicitArraySizes();

+        }

+    } finalLinkTraverser;

+

+    treeRoot->traverse(&finalLinkTraverser);

 }

 

 //

@@ -877,11 +914,8 @@
 

     // rules 5 and 7

     if (type.isMatrix()) {

-        TType derefType(type, 0);

-            

         // rule 5: deref to row, not to column, meaning the size of vector is num columns instead of num rows

-        if (type.getQualifier().layoutMatrix == ElmRowMajor)

-            derefType.setElementType(derefType.getBasicType(), type.getMatrixCols(), 0, 0, 0);

+        TType derefType(type, 0, type.getQualifier().layoutMatrix == ElmRowMajor);

             

         alignment = getBaseAlignment(derefType, size, std140);

         if (std140)

diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index 621772f..4ebbf2c 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -251,6 +251,7 @@
     void error(TInfoSink& infoSink, const char*);
     void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
     void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
+    void mergeImplicitArraySizes(TType&, const TType&);
     void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage);
     void checkCallGraphCycles(TInfoSink&);
     void inOutLocationCheck(TInfoSink&);
diff --git a/glslang/MachineIndependent/reflection.cpp b/glslang/MachineIndependent/reflection.cpp
index 07bba31..ac9f3b6 100644
--- a/glslang/MachineIndependent/reflection.cpp
+++ b/glslang/MachineIndependent/reflection.cpp
@@ -283,7 +283,7 @@
         bool block = base->getBasicType() == EbtBlock;

         if (block) {

             offset = 0;

-            anonymous = base->getName().compare(0, 6, "__anon") == 0;

+            anonymous = IsAnonymous(base->getName());

             if (base->getType().isArray()) {

                 assert(! anonymous);

                 for (int e = 0; e < base->getType().getArraySize(); ++e)