diff --git a/Test/300block.frag b/Test/300block.frag
index c6d9fcc8c50f2b16b26b2747b728e4188e88f0a9..25aab8ad18c0f26c3a09e23a55e44a75b348538a 100644
--- a/Test/300block.frag
+++ b/Test/300block.frag
@@ -34,6 +34,11 @@ uniform barBlockArray {
     int ni;
 } insts[4];
 
+uniform unreferenced {
+    float f;
+    uint u;
+};
+
 void main()
 {
     texture(s.sampler, vec3(inst.ni, bv.y, insts[2].nbv.z));
diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h
index f5a1d4445d93594dd66e6abf7c53e6c48ed741ec..ec11f617124b77094693447369a31c94270910ea 100644
--- a/glslang/Include/intermediate.h
+++ b/glslang/Include/intermediate.h
@@ -56,6 +56,7 @@
 enum TOperator {
     EOpNull,            // if in a node, should only mean a node is still being built
     EOpSequence,        // denotes a list of statements, or parameters, etc.
+    EOpLinkerObjects,   // for aggregate node of objects the linker may need, if not reference by the rest of the AST
     EOpFunctionCall,    
     EOpFunction,        // For function definition
     EOpParameters,      // an aggregate listing the parameters to a function
@@ -353,6 +354,7 @@ public:
     
     virtual TBasicType getBasicType() const { return type.getBasicType(); }
     virtual TQualifier& getQualifier() { return type.getQualifier(); }
+    virtual const TQualifier& getQualifier() const { return type.getQualifier(); }
     virtual void propagatePrecision(TPrecisionQualifier);
     virtual int getVectorSize() const { return type.getVectorSize(); }
     virtual int getMatrixCols() const { return type.getMatrixCols(); }
@@ -431,15 +433,15 @@ public:
 	// if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from
 	// per process globalpoolallocator, then it causes increased memory usage per compile
 	// it is essential to use "symbol = sym" to assign to symbol
-    TIntermSymbol(int i, const TString& sym, const TType& t) : 
-        TIntermTyped(t), id(i)  { symbol = sym;} 
+    TIntermSymbol(int i, const TString& n, const TType& t) : 
+        TIntermTyped(t), id(i)  { name = n;} 
     virtual int getId() const { return id; }
-    virtual const TString& getSymbol() const { return symbol;  }
+    virtual const TString& getName() const { return name; }
     virtual void traverse(TIntermTraverser*);
     virtual TIntermSymbol* getAsSymbolNode() { return this; }
 protected:
     int id;
-    TString symbol;
+    TString name;
 };
 
 class TIntermConstantUnion : public TIntermTyped {
@@ -519,12 +521,14 @@ public:
     virtual TIntermAggregate* getAsAggregate() { return this; }
     virtual void setOperator(TOperator o) { op = o; }
     virtual TIntermSequence& getSequence() { return sequence; }
+    virtual const TIntermSequence& getSequence() const { return sequence; }
 	virtual void setName(const TString& n) { name = n; }
     virtual const TString& getName() const { return name; }
     virtual void traverse(TIntermTraverser*);
     virtual void setUserDefined() { userDefined = true; }
     virtual bool isUserDefined() { return userDefined; }
     virtual TQualifierList& getQualifierList() { return qualifier; }
+    virtual const TQualifierList& getQualifierList() const { return qualifier; }
 	void setOptimize(bool o) { optimize = o; }
 	void setDebug(bool d) { debug = d; }
 	bool getOptimize() { return optimize; }
diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp
index 771bb17cc688150fb279a206e3618930b0cd27e2..df807e8d941a956ca44e2df3e8bfbe980a9576af 100644
--- a/glslang/MachineIndependent/Intermediate.cpp
+++ b/glslang/MachineIndependent/Intermediate.cpp
@@ -835,7 +835,7 @@ TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expres
 }
 
 //
-// This is to be executed once the final root is put on top by the parsing
+// This is to be executed after the final root is put on top by the parsing
 // process.
 //
 bool TIntermediate::postProcess(TIntermNode* root, EShLanguage language)
@@ -843,9 +843,7 @@ bool TIntermediate::postProcess(TIntermNode* root, EShLanguage language)
     if (root == 0)
         return true;
 
-    //
-    // First, finish off the top level sequence, if any
-    //
+    // Finish off the top-level sequence
     TIntermAggregate* aggRoot = root->getAsAggregate();
     if (aggRoot && aggRoot->getOp() == EOpNull)
         aggRoot->setOperator(EOpSequence);
@@ -853,6 +851,58 @@ bool TIntermediate::postProcess(TIntermNode* root, EShLanguage language)
     return true;
 }
 
+void TIntermediate::addSymbolLinkageNodes(TIntermNode* root, TIntermAggregate*& linkage, EShLanguage language, TSymbolTable& symbolTable)
+{
+    // Add top-level nodes for declarations that must be checked cross
+    // compilation unit by a linker, yet might not have been referenced
+    // by the AST.
+    //
+    // Almost entirely, translation of symbols is driven by what's present 
+    // 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 
+    //    gl_InstanceID are also considered active vertex attributes."
+    //  - Linker-based type mismatch error reporting needs to see all 
+    //    uniforms/ins/outs variables and blocks.
+    //  - ftransform() can make gl_Vertex and gl_ModelViewProjectionMatrix active.
+    //
+
+    //if (ftransformUsed) {
+        // TODO: desktop: track ftransform() usage
+    //    addSymbolLinkageNode(root, symbolTable, "gl_Vertex");
+    //    addSymbolLinkageNode(root, symbolTable, "gl_ModelViewProjectionMatrix");
+    //}
+
+    if (language == EShLangVertex) {
+        // the names won't be found in the symbol table unless the versions are right, 
+        // so version logic does not need to be repeated here
+        addSymbolLinkageNode(linkage, symbolTable, "gl_VertexID");
+        addSymbolLinkageNode(linkage, symbolTable, "gl_InstanceID");
+    }
+
+    if (linkage) {
+        // Finish off linkage sequence
+        linkage->setOperator(EOpLinkerObjects);
+
+        // Add a child to the root node for the linker objects
+        growAggregate(root, linkage, 0);
+    }
+}
+
+void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable& symbolTable, const TString& name)
+{
+    TSymbol* symbol = symbolTable.find(name);
+    if (symbol)
+        addSymbolLinkageNode(linkage, *symbol->getAsVariable());
+}
+
+void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, const TVariable& variable)
+{
+    TIntermSymbol* node = new TIntermSymbol(variable.getUniqueId(), variable.getName(), variable.getType());
+    linkage = growAggregate(linkage, node, 0);
+}
+
 //
 // This deletes the tree.
 //
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index a9040e95708819deec067f5ebc565be4d9701179..bf11314d83be470cdd0351ba65d6d726f546e93b 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -42,7 +42,7 @@
 
 TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, int v, EProfile p, EShLanguage L, TInfoSink& is,                             
                              bool fc, EShMessages m) : 
-            intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0),
+            intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0), linkage(0),
             numErrors(0), lexAfterType(false), loopNestingLevel(0),
             structNestingLevel(0), inTypeParen(false),
             version(v), profile(p), forwardCompatible(fc), messages(m),
@@ -331,11 +331,11 @@ void TParseContext::variableCheck(TIntermTyped*& nodePtr)
         return;
 
     if (symbol->getType().getBasicType() == EbtVoid) {
-        error(symbol->getLine(), "undeclared identifier", symbol->getSymbol().c_str(), "");
+        error(symbol->getLine(), "undeclared identifier", symbol->getName().c_str(), "");
 
         // Add to symbol table to prevent future error messages on the same name
             
-        TVariable* fakeVariable = new TVariable(&symbol->getSymbol(), TType(EbtFloat));
+        TVariable* fakeVariable = new TVariable(&symbol->getName(), TType(EbtFloat));
         symbolTable.insert(*fakeVariable);
 
         // substitute a symbol node for this new variable
@@ -403,7 +403,7 @@ bool TParseContext::lValueErrorCheck(int line, const char* op, TIntermTyped* nod
 
     const char* symbol = 0;
     if (symNode != 0)
-        symbol = symNode->getSymbol().c_str();
+        symbol = symNode->getName().c_str();
 
     const char* message = 0;
     switch (node->getQualifier().storage) {
@@ -1038,15 +1038,15 @@ void TParseContext::arrayCheck(int line, TString& identifier, const TPublicType&
 
 bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, bool updateFlag, TSourceLoc line)
 {
-    TSymbol* symbol = symbolTable.find(node->getSymbol());
+    TSymbol* symbol = symbolTable.find(node->getName());
     if (symbol == 0) {
-        error(line, " undeclared identifier", node->getSymbol().c_str(), "");
+        error(line, " undeclared identifier", node->getName().c_str(), "");
         return true;
     }
 
     TVariable* variable = symbol->getAsVariable();
     if (! variable) {
-        error(0, "array variable name expected", node->getSymbol().c_str(), "");
+        error(0, "array variable name expected", node->getName().c_str(), "");
         return true;
     }
 
@@ -1055,7 +1055,7 @@ bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size,
 
     // special casing to test index value of gl_TexCoord. If the accessed index is >= gl_MaxTextureCoords
     // its an error
-    if (node->getSymbol() == "gl_TexCoord") {
+    if (node->getName() == "gl_TexCoord") {
         TSymbol* texCoord = symbolTable.find("gl_MaxTextureCoords");
         if (! texCoord || ! texCoord->getAsVariable()) {
             infoSink.info.message(EPrefixInternalError, "gl_MaxTextureCoords not defined", line);
@@ -1111,11 +1111,15 @@ void TParseContext::nonInitCheck(int line, TString& identifier, TPublicType& typ
 
     TVariable* variable = new TVariable(&identifier, TType(type));
 
-    if (! symbolTable.insert(*variable)) {
+    if (! symbolTable.insert(*variable))
         error(line, "redefinition", variable->getName().c_str(), "");
-        delete variable;
-    } else
+    else {
         voidErrorCheck(line, identifier, type);
+
+        // see if it's a linker-level object to track
+        if (type.qualifier.isUniform() || type.qualifier.isPipeInput() || type.qualifier.isPipeOutput())
+            intermediate.addSymbolLinkageNode(linkage, *variable);
+    }
 }
 
 void TParseContext::paramCheck(int line, TStorageQualifier qualifier, TType* type)
@@ -1311,12 +1315,12 @@ bool TParseContext::executeInitializerError(TSourceLoc line, TString& identifier
                 variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
             }
         } else if (initializer->getAsSymbolNode()) {
-            TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol());
+            TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getName());
             if (TVariable* tVar = symbol->getAsVariable()) {
                 constUnion* constArray = tVar->getConstUnionPointer();
                 variable->shareConstPointer(constArray);
             } else {
-                error(line, "expected variable", initializer->getAsSymbolNode()->getSymbol().c_str(), "");
+                error(line, "expected variable", initializer->getAsSymbolNode()->getName().c_str(), "");
                 return true;
             }
         } else {
@@ -1575,7 +1579,7 @@ void TParseContext::addBlock(int line, TTypeList& typeList, const TString* insta
     case EvqOut:      defaultQualification = globalOutputDefaults;     break;
     default:          defaultQualification.clear();                    break;
     }
-    
+
     mergeLayoutQualifiers(line, defaultQualification, currentBlockDefaults);
     for (unsigned int member = 0; member < typeList.size(); ++member) {
         TQualifier memberQualification = defaultQualification;
@@ -1611,6 +1615,9 @@ void TParseContext::addBlock(int line, TTypeList& typeList, const TString* insta
 
         return;
     }
+
+    // save it in case there are no references in the AST, so the linker can error test against it
+    intermediate.addSymbolLinkageNode(linkage, *variable);
 }
 
 // For an identifier that is already declared, add more qualification to it.
diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h
index 43ec8fe54c9a0d4f46053fdb3a1987e376a31469..4d29186ead2e517caaff4c0cc1d413948900b8f8 100644
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -41,13 +41,6 @@
 #include "SymbolTable.h"
 #include "localintermediate.h"
 
-struct TMatrixFields {
-    bool wholeRow;
-    bool wholeCol;
-    int row;
-    int col;
-};
-
 typedef enum {
     EBhRequire,
     EBhEnable,
@@ -62,6 +55,8 @@ struct TPragma {
 	TPragmaTable pragmaTable;
 };
 
+
+
 //
 // The following are extra variables needed during parsing, grouped together so
 // they can be passed to the parser without needing a global.
@@ -74,6 +69,7 @@ struct TParseContext {
     TInfoSink& infoSink;
     EShLanguage language;        // vertex or fragment language
     TIntermNode* treeRoot;       // root of parse tree being created
+    TIntermAggregate *linkage;   // aggregate node of objects the linker may need, if not reference by the rest of the AST
     int numErrors;               // number of compile-time errors encountered
     bool lexAfterType;           // true if we've recognized a type, so can only be looking for an identifier
     int loopNestingLevel;        // 0 if outside all loops
diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp
index fe3ff88a2bb6883da7fc187497ea2ca422d95e3d..f2dbfd68a8517909f1413b84da442d108b49a591 100644
--- a/glslang/MachineIndependent/ShaderLang.cpp
+++ b/glslang/MachineIndependent/ShaderLang.cpp
@@ -556,6 +556,7 @@ int ShCompile(
     int ret = PaParseStrings(const_cast<char**>(shaderStrings), 0, numStrings, parseContext, parseContext.getPreamble());
     if (ret)
         success = false;
+    intermediate.addSymbolLinkageNodes(parseContext.treeRoot, parseContext.linkage, parseContext.language, symbolTable);
 
     if (success && parseContext.treeRoot) {
         if (optLevel == EShOptNoGeneration)
@@ -564,7 +565,6 @@ int ShCompile(
             success = intermediate.postProcess(parseContext.treeRoot, parseContext.language);
 
             if (success) {
-
                 if (debugOptions & EDebugOpIntermediate)
                     intermediate.outputTree(parseContext.treeRoot);
 
diff --git a/glslang/MachineIndependent/SymbolTable.h b/glslang/MachineIndependent/SymbolTable.h
index 10ffaa08e7271b0cd5581744cfc315d41cbc05a8..7932539353d4845fe0372cfdf72fc95eeb298d6f 100644
--- a/glslang/MachineIndependent/SymbolTable.h
+++ b/glslang/MachineIndependent/SymbolTable.h
@@ -442,6 +442,7 @@ public:
             *builtIn = level < 2;
         if (sameScope)
             *sameScope = level == currentLevel();
+
         return symbol;
     }
 
diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y
index 39003818cbea372d04ac9838161ddab59329a980..a5fa9072c79aa6f28ecc5c160922f87228d880c8 100644
--- a/glslang/MachineIndependent/glslang.y
+++ b/glslang/MachineIndependent/glslang.y
@@ -270,7 +270,7 @@ postfix_expression
         parseContext.variableCheck($1);
         if (!$1->isArray() && !$1->isMatrix() && !$1->isVector()) {
             if ($1->getAsSymbolNode())
-                parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", $1->getAsSymbolNode()->getSymbol().c_str(), "");
+                parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", $1->getAsSymbolNode()->getName().c_str(), "");
             else
                 parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", "expression", "");
         }
@@ -746,8 +746,8 @@ function_identifier
         } else {
             TIntermSymbol* symbol = $1->getAsSymbolNode();
             if (symbol) {
-                parseContext.reservedErrorCheck(symbol->getLine(), symbol->getSymbol());
-                TFunction *function = new TFunction(&symbol->getSymbol(), TType(EbtVoid));
+                parseContext.reservedErrorCheck(symbol->getLine(), symbol->getName());
+                TFunction *function = new TFunction(&symbol->getName(), TType(EbtVoid));
                 $$.function = function;
             } else
                 parseContext.error($1->getLine(), "function call, method or subroutine call expected", "", "");
diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp
index 944dedd854353e2cd95f082004ec7c7f54d434d6..fe0f233d8ea0ec618fe2200f548be30a93d7e788 100644
--- a/glslang/MachineIndependent/intermOut.cpp
+++ b/glslang/MachineIndependent/intermOut.cpp
@@ -87,7 +87,7 @@ void OutputSymbol(TIntermSymbol* node, TIntermTraverser* it)
     const int maxSize = GlslangMaxTypeLength + GlslangMaxTokenLength;
     char buf[maxSize];
     snprintf(buf, maxSize, "'%s' (%s)\n",
-           node->getSymbol().c_str(),
+           node->getName().c_str(),
            node->getCompleteString().c_str());
 
     oit->infoSink.debug << buf;
@@ -274,6 +274,7 @@ bool OutputAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTravers
 
     switch (node->getOp()) {
     case EOpSequence:      out.debug << "Sequence\n";       return true;
+    case EOpLinkerObjects: out.debug << "Linker Objects\n"; return true;
     case EOpComma:         out.debug << "Comma";            break;
     case EOpFunction:      out.debug << "Function Definition: " << node->getName(); break;
     case EOpFunctionCall:  out.debug << "Function Call: "       << node->getName(); break;
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index ab0c0db5ba97fb74c8a09caba4d62eca1160db15..4332d821b84ebb8c5d1b0e7d2c8509d2822e0700 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -80,6 +80,9 @@ public:
     TIntermBranch* addBranch(TOperator, TIntermTyped*, TSourceLoc);
     TIntermTyped* addSwizzle(TVectorFields&, TSourceLoc);
     bool postProcess(TIntermNode*, EShLanguage);
+    void addSymbolLinkageNodes(TIntermNode* root, TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
+    void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
+    void addSymbolLinkageNode(TIntermAggregate*& linkage, const TVariable&);
 	void remove(TIntermNode*);
     void outputTree(TIntermNode*);