diff --git a/Test/400.geom b/Test/400.geom
index 84461be9eedb95875baa075cf089a46871a48af2..5388bb6cf0b3681551d24737053a37d85965ae6a 100644
--- a/Test/400.geom
+++ b/Test/400.geom
@@ -12,3 +12,40 @@ void main()
 
 layout(invocations = 3) out outbn { int a; }; // ERROR, not on a block
 layout(max_vertices = 127, invocations = 4) out;
+
+#extension GL_ARB_separate_shader_objects : enable
+
+in gl_PerVertex {      // testing input arrays with a block redeclaration, see 420.geom for without
+    vec4 gl_Position;
+} gl_in[];
+
+void foo()
+{
+    gl_in.length();  // ERROR
+    gl_in[1].gl_Position;
+}
+
+in vec4 color[];
+in vec4 color2[];
+in vec4 colorS[3];
+in vec4 colorBad[4];
+
+void foo2()
+{
+    color.length(); // ERROR
+    colorS.length();
+}
+
+layout(triangles) in;  // give ERROR just for colorBad
+
+in vec4 color[3];
+in vec4 color2[3];
+in vec4 colorbad2[2];  // ERROR
+
+void foo3()
+{
+    gl_in.length();
+    color.length();
+    color2.length();
+    colorS.length();
+}
diff --git a/Test/420.geom b/Test/420.geom
new file mode 100644
index 0000000000000000000000000000000000000000..9740799cf3491725df1bbb6bda37da4f76456ebd
--- /dev/null
+++ b/Test/420.geom
@@ -0,0 +1,23 @@
+#version 150 core
+
+// testing input arrays without a gl_in[] block redeclaration, see 400.geom for with
+
+int i;
+
+void foo()
+{
+    gl_in.length();  // ERROR
+    gl_in[1].gl_Position;
+    gl_in[i].gl_Position;  // ERROR
+}
+
+layout(triangles) in;
+
+in vec4 color3[3];
+
+void foo3()
+{
+    gl_in.length();
+    gl_in[i].gl_Position;
+    color3.length();
+}
diff --git a/Test/baseResults/120.frag.out b/Test/baseResults/120.frag.out
index 340639f6df5fb94ba26e3ebd8d3f2145b5be4f64..5691aec8aafe2e3aaad0fa26c3614bead83518a1 100644
--- a/Test/baseResults/120.frag.out
+++ b/Test/baseResults/120.frag.out
@@ -300,7 +300,7 @@ ERROR: node is still EOpNull!
 0:121      add second child into first child (4-component vector of float)
 0:121        'v' (4-component vector of float)
 0:121        direct index (smooth in 4-component vector of float)
-0:121          'gl_TexCoord' (smooth in unsized array of 4-component vector of float)
+0:121          'gl_TexCoord' (smooth in 6-element array of 4-component vector of float)
 0:121          Constant:
 0:121            3 (const int)
 0:?   Linker Objects
diff --git a/Test/baseResults/130.frag.out b/Test/baseResults/130.frag.out
index 56965232ccd6b130462a9971a7c31ddce086778a..e26427567c2e3dc9b6a50a944f68f7d1c8eafca7 100644
--- a/Test/baseResults/130.frag.out
+++ b/Test/baseResults/130.frag.out
@@ -46,5 +46,6 @@ ERROR: node is still EOpNull!
 0:?     'fflat' (flat in float)
 0:?     'fsmooth' (smooth in float)
 0:?     'fnop' (noperspective in float)
+0:?     'gl_ClipDistance' (smooth in unsized array of float)
 0:?     'sampC' (uniform samplerCube)
 
diff --git a/Test/baseResults/140.frag.out b/Test/baseResults/140.frag.out
index 3edb07097fa80a8ee6eccca7fc730764ab2603dc..1660a16c4d15d744c1b39bbcb96a63b4b70815ce 100644
--- a/Test/baseResults/140.frag.out
+++ b/Test/baseResults/140.frag.out
@@ -19,4 +19,5 @@ ERROR: node is still EOpNull!
 0:?     'i' (smooth in 4-component vector of float)
 0:?     'o' (out 4-component vector of float)
 0:?     'gl_ClipDistance' (smooth in 5-element array of float)
+0:?     'gl_ClipDistance' (smooth in 5-element array of float)
 
diff --git a/Test/baseResults/150.geom.out b/Test/baseResults/150.geom.out
index 2a22ff5589aa367db495b43c82230138852dfc1d..57bbecd19532c01357207bb1e5d958a6a552d2c7 100644
--- a/Test/baseResults/150.geom.out
+++ b/Test/baseResults/150.geom.out
@@ -63,7 +63,7 @@ ERROR: node is still EOpNull!
 0:33        direct index (float)
 0:33          gl_ClipDistance: direct index for structure (unsized array of float)
 0:33            direct index (in block{gl_Position,gl_PointSize,gl_ClipDistance})
-0:33              'gl_in' (in unsized array of block{gl_Position,gl_PointSize,gl_ClipDistance})
+0:33              'gl_in' (in 4-element array of block{gl_Position,gl_PointSize,gl_ClipDistance})
 0:33              Constant:
 0:33                1 (const int)
 0:33            Constant:
@@ -77,7 +77,7 @@ ERROR: node is still EOpNull!
 0:34            0 (const uint)
 0:34        gl_Position: direct index for structure (4-component vector of float)
 0:34          direct index (in block{gl_Position,gl_PointSize,gl_ClipDistance})
-0:34            'gl_in' (in unsized array of block{gl_Position,gl_PointSize,gl_ClipDistance})
+0:34            'gl_in' (in 4-element array of block{gl_Position,gl_PointSize,gl_ClipDistance})
 0:34            Constant:
 0:34              0 (const int)
 0:34          Constant:
@@ -89,7 +89,7 @@ ERROR: node is still EOpNull!
 0:35            1 (const uint)
 0:35        gl_PointSize: direct index for structure (float)
 0:35          direct index (in block{gl_Position,gl_PointSize,gl_ClipDistance})
-0:35            'gl_in' (in unsized array of block{gl_Position,gl_PointSize,gl_ClipDistance})
+0:35            'gl_in' (in 4-element array of block{gl_Position,gl_PointSize,gl_ClipDistance})
 0:35            Constant:
 0:35              3 (const int)
 0:35          Constant:
@@ -119,6 +119,7 @@ ERROR: node is still EOpNull!
 0:?     'fromV' (in block{color})
 0:?     'toF' (layout(stream=0 ) out block{color})
 0:?     '__anon__0' (layout(stream=0 ) out block{color})
+0:?     'gl_in' (in 4-element array of block{gl_Position,gl_PointSize,gl_ClipDistance})
 0:?     'ov0' (layout(stream=0 ) out 4-component vector of float)
 0:?     'ov4' (layout(stream=4 ) out 4-component vector of float)
 0:?     'o1v0' (layout(stream=0 ) out 4-component vector of float)
diff --git a/Test/baseResults/400.frag.out b/Test/baseResults/400.frag.out
index 5fdb4fc9e9c44134aed69bfabac1ef8e2c9ea5d6..2a1b4186692aa8d9048bf85d0ba9ba0304912219 100644
--- a/Test/baseResults/400.frag.out
+++ b/Test/baseResults/400.frag.out
@@ -112,6 +112,7 @@ ERROR: node is still EOpNull!
 0:?     'arrayedSampler' (uniform 5-element array of sampler2D)
 0:?     'samp2dr' (uniform usampler2DRect)
 0:?     'isamp2DA' (uniform isampler2DArray)
+0:?     'gl_ClipDistance' (smooth in unsized array of float)
 0:?     'vl' (layout(location=4 ) smooth in 4-component vector of float)
 0:?     'vl2' (layout(location=4 ) smooth in 4-component vector of float)
 0:?     'uv3' (layout(location=3 ) uniform 3-component vector of float)
diff --git a/Test/baseResults/400.geom.out b/Test/baseResults/400.geom.out
index 93d603d0ab5e23e5face77ddc2b7f9faab18c8d7..2bbac98d29979a00f104c1d8051faba14feb3b6c 100644
--- a/Test/baseResults/400.geom.out
+++ b/Test/baseResults/400.geom.out
@@ -1,10 +1,14 @@
 Warning, version 400 is not yet complete; some version-specific features are present, but many are missing.
 ERROR: 0:13: 'invocations' : can only apply to a standalone qualifier 
-ERROR: 1 compilation errors.  No code generated.
+ERROR: 0:24: 'length' :  array must be declared with a size before using this method
+ERROR: 0:35: 'length' :  array must be declared with a size before using this method
+ERROR: 0:39: 'triangles' : inconsistent input primitive for array size colorBad
+ERROR: 0:43: 'triangles' : inconsistent input primitive for array size colorbad2
+ERROR: 5 compilation errors.  No code generated.
 
 invocations = 4
 max_vertices = 127
-input primitive = none
+input primitive = triangles
 output primitive = none
 ERROR: node is still EOpNull!
 0:3  Function Definition: main( (void)
@@ -22,6 +26,42 @@ ERROR: node is still EOpNull!
 0:10        move second child to first child (int)
 0:10          'id' (int)
 0:10          'gl_InvocationID' (in int)
+0:22  Function Definition: foo( (void)
+0:22    Function Parameters: 
+0:24    Sequence
+0:24      Constant:
+0:24        1 (const int)
+0:25      gl_Position: direct index for structure (4-component vector of float)
+0:25        direct index (in block{gl_Position})
+0:25          'gl_in' (in 3-element array of block{gl_Position})
+0:25          Constant:
+0:25            1 (const int)
+0:25        Constant:
+0:25          0 (const int)
+0:33  Function Definition: foo2( (void)
+0:33    Function Parameters: 
+0:35    Sequence
+0:35      Constant:
+0:35        1 (const int)
+0:36      Constant:
+0:36        3 (const int)
+0:45  Function Definition: foo3( (void)
+0:45    Function Parameters: 
+0:47    Sequence
+0:47      Constant:
+0:47        3 (const int)
+0:48      Constant:
+0:48        3 (const int)
+0:49      Constant:
+0:49        3 (const int)
+0:50      Constant:
+0:50        3 (const int)
 0:?   Linker Objects
 0:?     '__anon__0' (layout(stream=0 ) out block{a})
+0:?     'gl_in' (in 3-element array of block{gl_Position})
+0:?     'color' (in 3-element array of 4-component vector of float)
+0:?     'color2' (in 3-element array of 4-component vector of float)
+0:?     'colorS' (in 3-element array of 4-component vector of float)
+0:?     'colorBad' (in 4-element array of 4-component vector of float)
+0:?     'colorbad2' (in 2-element array of 4-component vector of float)
 
diff --git a/Test/baseResults/410.geom.out b/Test/baseResults/410.geom.out
index f922453daec2a137e83796c771c9f19cf982d00b..a9a3c5efba5395fed36e287a24556348cae7b955 100644
--- a/Test/baseResults/410.geom.out
+++ b/Test/baseResults/410.geom.out
@@ -2,7 +2,7 @@ Warning, version 410 is not yet complete; some version-specific features are pre
 ERROR: 0:8: 'myIn' : cannot redeclare a built-in block with a user name 
 ERROR: 0:8: 'gl_' : reserved built-in name 
 ERROR: 0:12: 'gl_' : reserved built-in name 
-ERROR: 0:20: 'gl_PerVertex' : can only redeclare a built-in block once 
+ERROR: 0:20: 'gl_PerVertex' : can only redeclare a built-in block once, and before any use 
 ERROR: 0:20: 'gl_' : reserved built-in name 
 ERROR: 5 compilation errors.  No code generated.
 
diff --git a/Test/baseResults/420.geom.out b/Test/baseResults/420.geom.out
new file mode 100644
index 0000000000000000000000000000000000000000..1c2907f63edde0f9e9619f976f97d9dfc6afd3e4
--- /dev/null
+++ b/Test/baseResults/420.geom.out
@@ -0,0 +1,46 @@
+Warning, version 150 is not yet complete; some version-specific features are present, but many are missing.
+ERROR: 0:9: 'length' :  array must be declared with a size before using this method
+ERROR: 0:11: '[' :  array must be redeclared with a size before being indexed with a variable
+ERROR: 2 compilation errors.  No code generated.
+
+invocations = 0
+max_vertices = 0
+input primitive = triangles
+output primitive = none
+ERROR: node is still EOpNull!
+0:7  Function Definition: foo( (void)
+0:7    Function Parameters: 
+0:9    Sequence
+0:9      Constant:
+0:9        1 (const int)
+0:10      gl_Position: direct index for structure (4-component vector of float)
+0:10        direct index (in block{gl_Position,gl_PointSize,gl_ClipDistance})
+0:10          'gl_in' (in 3-element array of block{gl_Position,gl_PointSize,gl_ClipDistance})
+0:10          Constant:
+0:10            1 (const int)
+0:10        Constant:
+0:10          0 (const int)
+0:11      gl_Position: direct index for structure (4-component vector of float)
+0:11        indirect index (in block{gl_Position,gl_PointSize,gl_ClipDistance})
+0:11          'gl_in' (in 3-element array of block{gl_Position,gl_PointSize,gl_ClipDistance})
+0:11          'i' (int)
+0:11        Constant:
+0:11          0 (const int)
+0:18  Function Definition: foo3( (void)
+0:18    Function Parameters: 
+0:20    Sequence
+0:20      Constant:
+0:20        3 (const int)
+0:21      gl_Position: direct index for structure (4-component vector of float)
+0:21        indirect index (in block{gl_Position,gl_PointSize,gl_ClipDistance})
+0:21          'gl_in' (in 3-element array of block{gl_Position,gl_PointSize,gl_ClipDistance})
+0:21          'i' (int)
+0:21        Constant:
+0:21          0 (const int)
+0:22      Constant:
+0:22        3 (const int)
+0:?   Linker Objects
+0:?     'i' (int)
+0:?     'gl_in' (in 3-element array of block{gl_Position,gl_PointSize,gl_ClipDistance})
+0:?     'color3' (in 3-element array of 4-component vector of float)
+
diff --git a/Test/baseResults/specExamples.frag.out b/Test/baseResults/specExamples.frag.out
index 7c155080c84dd3f1b6ccec421082035cb07c5afc..de312ae814f786f590c482ed938017e6a2c6017f 100644
--- a/Test/baseResults/specExamples.frag.out
+++ b/Test/baseResults/specExamples.frag.out
@@ -286,8 +286,11 @@ ERROR: node is still EOpNull!
 0:?     '__anon__1' (in block{LightPos,LightColor})
 0:?     'Materiala' (in block{Color,TexCoord})
 0:?     'gl_FragCoord' (gl_FragCoord 4-component vector of float)
+0:?     'gl_FragCoord' (gl_FragCoord 4-component vector of float)
 0:?     'factor' (layout(location=3 ) out 4-component vector of float)
 0:?     'colors' (layout(location=2 ) out 3-element array of 4-component vector of float)
 0:?     'gl_FragDepth' (gl_FragDepth float)
+0:?     'gl_FragDepth' (gl_FragDepth float)
+0:?     '__anon__2' (in block{gl_FogFragCoord,gl_TexCoord,gl_Color,gl_SecondaryColor})
 0:?     '__anon__2' (in block{gl_FogFragCoord,gl_TexCoord,gl_Color,gl_SecondaryColor})
 
diff --git a/Test/baseResults/specExamples.vert.out b/Test/baseResults/specExamples.vert.out
index cfebc5a1ff40abb673d862ef59f89b51000fd168..030d42ef4bd4cefd3cfd267ad67aa5098d34c6b3 100644
--- a/Test/baseResults/specExamples.vert.out
+++ b/Test/baseResults/specExamples.vert.out
@@ -294,6 +294,7 @@ ERROR: node is still EOpNull!
 0:?     'c2' (layout(binding=3 ) uniform int)
 0:?     'd2' (layout(binding=2 ) uniform int)
 0:?     '__anon__5' (out block{gl_Position,gl_PointSize,gl_ClipDistance,gl_ClipVertex,gl_FrontColor,gl_BackColor,gl_FrontSecondaryColor,gl_BackSecondaryColor,gl_TexCoord,gl_FogFragCoord})
+0:?     '__anon__5' (out block{gl_Position,gl_PointSize,gl_ClipDistance,gl_ClipVertex,gl_FrontColor,gl_BackColor,gl_FrontSecondaryColor,gl_BackSecondaryColor,gl_TexCoord,gl_FogFragCoord})
 0:?     'ColorInv' (smooth out 3-component vector of float)
 0:?     'Color4' (invariant centroid smooth out 3-component vector of float)
 0:?     'position' (smooth out 4-component vector of float)
diff --git a/Test/baseResults/varyingArray.frag.out b/Test/baseResults/varyingArray.frag.out
index 73f7b906e700c33950a3ceb9fd14a7fa0382cee8..d8d0cdca36a651b73440e3bd11fa7350633915a4 100644
--- a/Test/baseResults/varyingArray.frag.out
+++ b/Test/baseResults/varyingArray.frag.out
@@ -54,5 +54,6 @@ WARNING: 0:8: varying deprecated in version 130; may be removed in future releas
 0:?     'color' (smooth in 4-component vector of float)
 0:?     'alpha' (smooth in float)
 0:?     'gl_TexCoord' (smooth in 6-element array of 4-component vector of float)
+0:?     'gl_TexCoord' (smooth in 6-element array of 4-component vector of float)
 0:?     'foo' (smooth in 3-element array of 4-component vector of float)
 
diff --git a/Test/baseResults/varyingArrayIndirect.frag.out b/Test/baseResults/varyingArrayIndirect.frag.out
index 8e605226813d7b289109031e38aa722be7ac6179..311638f673e8e9dcd61360882b110e2f028fce77 100644
--- a/Test/baseResults/varyingArrayIndirect.frag.out
+++ b/Test/baseResults/varyingArrayIndirect.frag.out
@@ -55,6 +55,7 @@ WARNING: 0:8: varying deprecated in version 130; may be removed in future releas
 0:?     'color' (smooth in 4-component vector of float)
 0:?     'alpha' (smooth in float)
 0:?     'gl_TexCoord' (smooth in 6-element array of 4-component vector of float)
+0:?     'gl_TexCoord' (smooth in 6-element array of 4-component vector of float)
 0:?     'userIn' (smooth in 2-element array of 4-component vector of float)
 0:?     'a' (uniform int)
 0:?     'b' (uniform int)
diff --git a/Test/testlist b/Test/testlist
index 0e0f2e182c2ee68c818b32f9237e75cad8c4ee20..aebde4a53cb38c84250357880224826f3cc42e89 100644
--- a/Test/testlist
+++ b/Test/testlist
@@ -47,6 +47,7 @@ tokenLength.vert
 300scope.vert
 400.frag
 420.vert
+420.geom
 430scope.vert
 lineContinuation.vert
 numeral.frag
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 1b12ce725719ae36f6f476e094d0c5e23ff740c1..7abc7beec96ae621c7af5961323896cdf740c24b 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -423,7 +423,7 @@ TIntermTyped* TParseContext::handleVariable(TSourceLoc loc, TSymbol* symbol, TSt
     } else {
         // The symbol table search was done in the lexical phase, but
         // if this is a new symbol, it wouldn't have found it.
-        const TVariable* variable = symbol ? symbol->getAsVariable() : 0;
+        TVariable* variable = symbol ? symbol->getAsVariable() : 0;
         if (symbol && ! variable)
             error(loc, "variable name expected", string->c_str(), "");
 
@@ -435,8 +435,16 @@ TIntermTyped* TParseContext::handleVariable(TSourceLoc loc, TSymbol* symbol, TSt
 
         if (variable->getType().getQualifier().storage == EvqConst)
             node = intermediate.addConstantUnion(variable->getConstArray(), variable->getType(), loc);
-        else
-            node = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), loc);
+        else {
+            // break sharing with built-ins
+            TType* type;
+            if (variable->isReadOnly()) {
+                type = new TType;
+                type->deepCopy(variable->getType());
+            } else
+                type = &variable->getWritableType();
+            node = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), *type, loc);
+        }
     }
 
     return node;
@@ -470,6 +478,7 @@ TIntermTyped* TParseContext::handleBracketDereference(TSourceLoc loc, TIntermTyp
             result = addConstMatrixNode(index->getAsConstantUnion()->getConstArray()[0].getIConst(), base, loc);
         }
     } else {
+        // at least one of base and index is variable...
         if (index->getQualifier().storage == EvqConst) {
             int indexValue = index->getAsConstantUnion()->getConstArray()[0].getIConst();
             if (! base->isArray() && ((base->isVector() && base->getType().getVectorSize() <= indexValue) ||
@@ -488,7 +497,7 @@ TIntermTyped* TParseContext::handleBracketDereference(TSourceLoc loc, TIntermTyp
                 error(loc, "", "[", "array must be redeclared with a size before being indexed with a variable");
             if (base->getBasicType() == EbtBlock)
                 requireProfile(base->getLoc(), ~EEsProfile, "variable indexing block array");
-            if (base->getBasicType() == EbtSampler && version >= 130) {
+            else if (base->getBasicType() == EbtSampler && version >= 130) {
                 const char* explanation = "variable indexing sampler array";
                 requireProfile(base->getLoc(), ECoreProfile | ECompatibilityProfile, explanation);
                 profileRequires(base->getLoc(), ECoreProfile | ECompatibilityProfile, 400, 0, explanation);
@@ -510,25 +519,90 @@ TIntermTyped* TParseContext::handleBracketDereference(TSourceLoc loc, TIntermTyp
         newType.dereference();
         result->setType(newType);
 
-        if (anyIndexLimits) {
-            // for ES 2.0 (version 100) limitations for almost all index operations except vertex-shader uniforms
-            if ((! limits.generalSamplerIndexing && base->getBasicType() == EbtSampler) ||
-                (! limits.generalUniformIndexing && base->getQualifier().isUniform() && language != EShLangVertex) ||
-                (! limits.generalAttributeMatrixVectorIndexing && base->getQualifier().isPipeInput() && language == EShLangVertex && (base->getType().isMatrix() || base->getType().isVector())) ||
-                (! limits.generalConstantMatrixVectorIndexing && base->getAsConstantUnion()) ||
-                (! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniform() && 
-                                                     ! base->getType().getQualifier().isPipeInput() && 
-                                                     ! base->getType().getQualifier().isPipeOutput() &&
-                                                       base->getType().getQualifier().storage != EvqConst) ||
-                (! limits.generalVaryingIndexing && (base->getType().getQualifier().isPipeInput() || 
-                                                     base->getType().getQualifier().isPipeOutput()))) {            
-                // it's too early to know what the inductive variables are, save it for post processing
-                needsIndexLimitationChecking.push_back(index);
+        if (anyIndexLimits)
+            handleIndexLimits(loc, base, index);
+
+        if (language == EShLangGeometry && base->isArray())
+            handleInputArrayAccess(loc, base);
+    }
+
+    return result;
+}
+
+// for ES 2.0 (version 100) limitations for almost all index operations except vertex-shader uniforms
+void TParseContext::handleIndexLimits(TSourceLoc loc, TIntermTyped* base, TIntermTyped* index)
+{
+    if ((! limits.generalSamplerIndexing && base->getBasicType() == EbtSampler) ||
+        (! limits.generalUniformIndexing && base->getQualifier().isUniform() && language != EShLangVertex) ||
+        (! limits.generalAttributeMatrixVectorIndexing && base->getQualifier().isPipeInput() && language == EShLangVertex && (base->getType().isMatrix() || base->getType().isVector())) ||
+        (! limits.generalConstantMatrixVectorIndexing && base->getAsConstantUnion()) ||
+        (! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniform() &&
+                                                ! base->getType().getQualifier().isPipeInput() &&
+                                                ! base->getType().getQualifier().isPipeOutput() &&
+                                                base->getType().getQualifier().storage != EvqConst) ||
+        (! limits.generalVaryingIndexing && (base->getType().getQualifier().isPipeInput() ||
+                                                base->getType().getQualifier().isPipeOutput()))) {
+        // it's too early to know what the inductive variables are, save it for post processing
+        needsIndexLimitationChecking.push_back(index);
+    }
+}
+
+// Handle a dereference of a geometry shader input arrays.
+// See inputArrayNodeResizeList comment in ParseHelper.h.
+//
+void TParseContext::handleInputArrayAccess(TSourceLoc loc, TIntermTyped* base)
+{
+    if (base->getType().getQualifier().storage == EvqVaryingIn) {
+        TIntermSymbol* symbol = base->getAsSymbolNode();
+        assert(symbol);
+        inputArrayNodeResizeList.push_back(symbol);
+        if (symbol && builtInName(symbol->getName())) {
+            // make sure we have a user-modifiable copy of this built-in input array
+            TSymbol* input = symbolTable.find(symbol->getName());
+            if (input->isReadOnly()) {
+                input = symbolTable.copyUp(input);
+                inputArraySymbolResizeList.push_back(input);
+
+                // Save it in the AST for linker use.
+                intermediate.addSymbolLinkageNode(linkage, *input);
             }
         }
     }
+}
 
-    return result;
+// If there has been an input primitive declaration, make sure all input array types
+// match it in size.  Types come either from nodes in the AST or symbols in the 
+// symbol table.
+//
+// Types without an array size will be given one.
+// Types already having a size that is wrong will get an error.
+//
+void TParseContext::checkInputArrayConsistency(TSourceLoc loc, bool tailOnly)
+{
+    TLayoutGeometry primitive = intermediate.getInputPrimitive();
+    if (primitive == ElgNone)
+        return;
+
+    if (tailOnly) {
+        checkInputArrayConsistency(loc, primitive, inputArraySymbolResizeList.back()->getWritableType(), inputArraySymbolResizeList.back()->getName());
+        return;
+    }
+
+    for (size_t i = 0; i < inputArrayNodeResizeList.size(); ++i)
+        checkInputArrayConsistency(loc, primitive, inputArrayNodeResizeList[i]->getWritableType(), inputArrayNodeResizeList[i]->getName());
+
+    for (size_t i = 0; i < inputArraySymbolResizeList.size(); ++i)
+        checkInputArrayConsistency(loc, primitive, inputArraySymbolResizeList[i]->getWritableType(), inputArraySymbolResizeList[i]->getName());
+}
+
+void TParseContext::checkInputArrayConsistency(TSourceLoc loc, TLayoutGeometry primitive, TType& type, const TString& name)
+{
+    int requiredSize = TQualifier::mapGeometryToSize(primitive);
+
+    if (type.getArraySize() == 0)
+        type.changeArraySize(requiredSize);
+    else if (type.getArraySize() != requiredSize)
+        error(loc, "inconsistent input primitive for array size", TQualifier::getGeometryString(primitive), name.c_str());
 }
 
 //
@@ -1052,7 +1126,7 @@ TOperator TParseContext::mapTypeToConstructorOp(const TType& type)
         default: break; // some compilers want this
         }
         break;
-    default: 
+    default:
         op = EOpNull;
         break;
     }
@@ -1268,7 +1342,7 @@ void TParseContext::globalCheck(TSourceLoc loc, const char* token)
 bool TParseContext::reservedErrorCheck(TSourceLoc loc, const TString& identifier)
 {
     if (! symbolTable.atBuiltInLevel()) {
-        if (identifier.compare(0, 3, "gl_") == 0) {
+        if (builtInName(identifier)) {
             error(loc, "reserved built-in name", "gl_", "");
 
             return true;
@@ -1283,6 +1357,11 @@ bool TParseContext::reservedErrorCheck(TSourceLoc loc, const TString& identifier
     return false;
 }
 
+bool TParseContext::builtInName(const TString& identifier)
+{
+    return identifier.compare(0, 3, "gl_") == 0;
+}
+
 //
 // Make sure there is enough data provided to the constructor to build
 // something of the type of the constructor.  Also returns the type of
@@ -1787,6 +1866,13 @@ void TParseContext::declareArray(TSourceLoc loc, TString& identifier, const TTyp
             symbol = new TVariable(&identifier, type);
             symbolTable.insert(*symbol);
             newDeclaration = true;
+
+            // Handle user geometry shader input arrays: see inputArrayNodeResizeList comment in ParseHelper.h
+            if (language == EShLangGeometry && type.getQualifier().storage == EvqVaryingIn && ! symbolTable.atBuiltInLevel()) {
+                inputArraySymbolResizeList.push_back(symbol);
+                checkInputArrayConsistency(loc, true);
+            }
+
             return;
         }
         if (symbol->getAsAnonMember()) {
@@ -1811,16 +1897,21 @@ void TParseContext::declareArray(TSourceLoc loc, TString& identifier, const TTyp
         return;
     }
     if (newType.getArraySize() > 0) {
-        error(loc, "redeclaration of array with size", identifier.c_str(), "");
+        // be more leniant for input arrays to geometry shaders, where the redeclaration is the same size
+        if (! (language == EShLangGeometry && type.getQualifier().storage == EvqVaryingIn && newType.getArraySize() == type.getArraySize()))
+            error(loc, "redeclaration of array with size", identifier.c_str(), "");
         return;
     }
 
     if (! newType.sameElementType(type)) {
-        error(loc, "redeclaration of array with a different newType", identifier.c_str(), "");
+        error(loc, "redeclaration of array with a different type", identifier.c_str(), "");
         return;
     }
 
     newType.shareArraySizes(type);
+
+    if (language == EShLangGeometry && type.getQualifier().storage == EvqVaryingIn)
+        checkInputArrayConsistency(loc);
 }
 
 void TParseContext::updateMaxArraySize(TSourceLoc loc, TIntermNode *node, int index)
@@ -1850,8 +1941,16 @@ void TParseContext::updateMaxArraySize(TSourceLoc loc, TIntermNode *node, int in
 
     // For read-only built-ins, add a new variable for holding the maximum array size of an implicitly-sized shared array.
     // TODO: functionality: unsized arrays: is this new array type shared with the node?
-    if (symbol->isReadOnly())
+    if (symbol->isReadOnly()) {
         symbol = symbolTable.copyUp(symbol);
+        
+        // Handle geometry shader input arrays: see inputArrayNodeResizeList comment in ParseHelper.h
+        if (language == EShLangGeometry && symbol->getType().getQualifier().storage == EvqVaryingIn)
+            inputArraySymbolResizeList.push_back(symbol);
+
+        // Save it in the AST for linker use.
+        intermediate.addSymbolLinkageNode(linkage, *symbol);
+    }
 
     symbol->getWritableType().setMaxArraySize(index + 1);
 }
@@ -1864,7 +1963,7 @@ void TParseContext::nonInitConstCheck(TSourceLoc loc, TString& identifier, TType
     //
     // Make the qualifier make sense, given that there is an initializer.
     //
-    if (type.getQualifier().storage == EvqConst || 
+    if (type.getQualifier().storage == EvqConst ||
         type.getQualifier().storage == EvqConstReadOnly) {
         type.getQualifier().storage = EvqTemporary;
         error(loc, "variables with qualifier 'const' must be initialized", identifier.c_str(), "");
@@ -1883,7 +1982,7 @@ void TParseContext::nonInitConstCheck(TSourceLoc loc, TString& identifier, TType
 //
 TSymbol* TParseContext::redeclareBuiltinVariable(TSourceLoc loc, const TString& identifier, bool& newDeclaration)
 {
-    if (profile == EEsProfile || identifier.compare(0, 3, "gl_") != 0 || symbolTable.atBuiltInLevel())
+    if (profile == EEsProfile || ! builtInName(identifier) || symbolTable.atBuiltInLevel())
         return 0;
 
     // Potentially redeclaring a built-in variable...
@@ -1915,6 +2014,13 @@ TSymbol* TParseContext::redeclareBuiltinVariable(TSourceLoc loc, const TString&
             // Copy the symbol up to make a writable version
             newDeclaration = true;
             symbol = symbolTable.copyUp(symbol);
+
+            // Handle geometry shader input arrays: see inputArrayNodeResizeList comment in ParseHelper.h
+            if (language == EShLangGeometry && symbol->getType().getQualifier().storage == EvqVaryingIn && symbol->getType().isArray())
+                inputArraySymbolResizeList.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.
@@ -1929,10 +2035,10 @@ TSymbol* TParseContext::redeclareBuiltinVariable(TSourceLoc loc, const TString&
 bool TParseContext::redeclareBuiltinBlock(TSourceLoc loc, TTypeList& typeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes)
 {
     // just a quick out, not everything that must be checked:
-    if (symbolTable.atBuiltInLevel() || profile == EEsProfile || blockName.compare(0, 3, "gl_") != 0)
+    if (symbolTable.atBuiltInLevel() || profile == EEsProfile || ! builtInName(blockName))
         return false;
 
-    if (instanceName && instanceName->compare(0, 3, "gl_") != 0) {
+    if (instanceName && ! builtInName(*instanceName)) {
         error(loc, "cannot redeclare a built-in block with a user name", instanceName->c_str(), "");
         return false;
     }
@@ -1944,11 +2050,8 @@ bool TParseContext::redeclareBuiltinBlock(TSourceLoc loc, TTypeList& typeList, c
     if (blockName != "gl_PerVertex" && blockName != "gl_PerFragment")
         return false;
 
-
     // Blocks with instance names are easy to find, lookup the instance name,
-    // Anonymous blocks need to be found via a member.  copyUp()?? will work 
-    // just fine for either find.
-
+    // Anonymous blocks need to be found via a member.
     bool builtIn;
     TSymbol* block;
     if (instanceName)
@@ -1964,7 +2067,7 @@ bool TParseContext::redeclareBuiltinBlock(TSourceLoc loc, TTypeList& typeList, c
     // Built-in blocks cannot be redeclared more than once, which if happened,
     // we'd be finding the already redeclared one here, rather than the built in.
     if (! builtIn) {
-        error(loc, "can only redeclare a built-in block once", blockName.c_str(), "");
+        error(loc, "can only redeclare a built-in block once, and before any use", blockName.c_str(), "");
         return false;
     }
 
@@ -1976,6 +2079,10 @@ bool TParseContext::redeclareBuiltinBlock(TSourceLoc loc, TTypeList& typeList, c
         return false;
     }
 
+    // Handle geometry shader input arrays: see inputArrayNodeResizeList comment in ParseHelper.h
+    if (language == EShLangGeometry && block->getType().isArray() && block->getType().getQualifier().storage == EvqVaryingIn)
+        inputArraySymbolResizeList.push_back(block);
+
     // TODO: semantics: block redeclaration: instance array size matching?
 
     // Edit and error check the container against the redeclaration
@@ -2061,7 +2168,7 @@ void TParseContext::arrayObjectCheck(TSourceLoc loc, const TType& type, const ch
 // "The loop index has type int or float.
 //
 // "The for statement has the form:
-//     for ( init-declaration ; condition ; expression ) 
+//     for ( init-declaration ; condition ; expression )
 //     init-declaration has the form: type-specifier identifier = constant-expression
 //     condition has the form:  loop-index relational_operator constant-expression
 //         where relational_operator is one of: > >= < <= == or !=
@@ -2102,11 +2209,11 @@ void TParseContext::inductiveLoopCheck(TSourceLoc loc, TIntermNode* init, TInter
         error(loc, "inductive-loop init-declaration requires the form \"type-specifier loop-index = constant-expression\"", "limitations", "");
         return;
     }
-    
+
     // get the unique id of the loop index
     int loopIndex = binaryInit->getLeft()->getAsSymbolNode()->getId();
     inductiveLoopIds.insert(loopIndex);
-    
+
     // condition's form must be "loop-index relational-operator constant-expression"
     bool badCond = ! loop->getTest();
     if (! badCond) {
@@ -2340,7 +2447,7 @@ void TParseContext::layoutTypeCheck(TSourceLoc loc, const TSymbol& symbol)
 
     // first, qualifier only error checking
     layoutQualifierCheck(loc, qualifier);
-    
+
     // now, error checking combining type and qualifier
     if (qualifier.hasLocation()) {
         switch (qualifier.storage) {
@@ -2372,10 +2479,10 @@ void TParseContext::layoutTypeCheck(TSourceLoc loc, const TSymbol& symbol)
     if (qualifier.hasBinding()) {
         // Binding checking, from the spec:
         //
-        // "If the binding point for any uniform or shader storage block instance is less than zero, or greater than or 
-        // equal to the implementation-dependent maximum number of uniform buffer bindings, a compile-time 
-        // error will occur. When the binding identifier is used with a uniform or shader storage block instanced as 
-        // an array of size N, all elements of the array from binding through binding + N – 1 must be within this 
+        // "If the binding point for any uniform or shader storage block instance is less than zero, or greater than or
+        // equal to the implementation-dependent maximum number of uniform buffer bindings, a compile-time
+        // error will occur. When the binding identifier is used with a uniform or shader storage block instanced as
+        // an array of size N, all elements of the array from binding through binding + N – 1 must be within this
         // range."
         //
         // TODO:  binding error checking against limits, arrays
@@ -2599,7 +2706,7 @@ TIntermNode* TParseContext::executeInitializer(TSourceLoc loc, TString& identifi
     initializer = convertInitializerList(loc, variable->getType(), initializer);
     if (! initializer) {
         // error recovery; don't leave const without constant values
-        if (qualifier == EvqConst)            
+        if (qualifier == EvqConst)
             variable->getWritableType().getQualifier().storage = EvqTemporary;
         return 0;
     }
@@ -2669,13 +2776,13 @@ TIntermTyped* TParseContext::convertInitializerList(TSourceLoc loc, const TType&
     // Will operate recursively.  Once a subtree is found that is constructor style,
     // everything below it is already good: Only the "top part" of the initializer
     // can be an initializer list, where "top part" can extend for several (or all) levels.
-    
+
     // see if we have bottomed out in the tree within the initializer-list part
     TIntermAggregate* initList = initializer->getAsAggregate();
     if (! initList || initList->getOp() != EOpNull)
         return initializer;
 
-    // Of the initializer-list set of nodes, need to process bottom up, 
+    // Of the initializer-list set of nodes, need to process bottom up,
     // so recurse deep, then process on the way up.
 
     // Go down the tree here...
@@ -2929,7 +3036,7 @@ TIntermTyped* TParseContext::constructStruct(TIntermNode* node, const TType& typ
 //
 void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TString* instanceName, TArraySizes* arraySizes)
 {
-    // This might be a redeclaration of a built-in block, find out, and get 
+    // This might be a redeclaration of a built-in block, find out, and get
     // a modifiable copy if so.
     if (redeclareBuiltinBlock(loc, typeList, *blockName, instanceName, arraySizes))
         return;
@@ -3013,7 +3120,7 @@ void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TStr
     // reverse merge, so that currentBlockQualifier now has all layout information
     // (can't use defaultQualification directly, it's missing other non-layout-default-class qualifiers)
     mergeObjectLayoutQualifiers(loc, currentBlockQualifier, defaultQualification);
-    
+
     TType blockType(&typeList, *blockName, currentBlockQualifier);
     if (arraySizes)
         blockType.setArraySizes(arraySizes);
@@ -3022,9 +3129,9 @@ void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TStr
     // Don't make a user-defined type out of block name; that will cause an error
     // if the same block name gets reused in a different interface.
     //
-    // "Block names have no other use within a shader 
-    // beyond interface matching; it is a compile-time error to use a block name at global scope for anything 
-    // other than as a block name (e.g., use of a block name for a global variable name or function name is 
+    // "Block names have no other use within a shader
+    // beyond interface matching; it is a compile-time error to use a block name at global scope for anything
+    // other than as a block name (e.g., use of a block name for a global variable name or function name is
     // currently reserved)."
     //
     // Use the symbol table to prevent normal reuse of the block's name, as a variable entry,
@@ -3124,7 +3231,9 @@ void TParseContext::updateStandaloneQualifierDefaults(TSourceLoc loc, const TPub
             case ElgLinesAdjacency:
             case ElgTriangles:
             case ElgTrianglesAdjacency:
-                if (! intermediate.setInputPrimitive(publicType.geometry))
+                if (intermediate.setInputPrimitive(publicType.geometry))
+                    checkInputArrayConsistency(loc);
+                else
                     error(loc, "cannot change previously set input primitive", TQualifier::getGeometryString(publicType.geometry), "");
                 break;
             default:
@@ -3178,7 +3287,7 @@ void TParseContext::updateStandaloneQualifierDefaults(TSourceLoc loc, const TPub
         error(loc, "default qualifier requires 'uniform', 'buffer', 'in', or 'out' storage qualification", "", "");
         return;
     }
-    
+
     if (qualifier.hasBinding())
         error(loc, "cannot declare a default, include a type or full declaration", "binding", "");
     if (qualifier.hasLocation())
diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h
index 9504e51a39276427077d5c1fa216ea1430333ffd..eab5fb7d3e84a35efdb40fb27a2ff3e253fad517 100644
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -72,12 +72,17 @@ public:
                       const char *szExtraInfoFormat, ...);
     void C_DECL  warn(TSourceLoc, const char *szReason, const char *szToken,
                       const char *szExtraInfoFormat, ...);
-    bool reservedErrorCheck(TSourceLoc, const TString& identifier);
+    bool reservedErrorCheck(TSourceLoc, const TString&);
+    bool builtInName(const TString&);
 
     void updateExtensionBehavior(const char* extName, const char* behavior);
     void handlePragma(const char **tokens, int numTokens);
     TIntermTyped* handleVariable(TSourceLoc, TSymbol* symbol, TString* string);
     TIntermTyped* handleBracketDereference(TSourceLoc, TIntermTyped* base, TIntermTyped* index);
+    void handleIndexLimits(TSourceLoc, TIntermTyped* base, TIntermTyped* index);
+    void handleInputArrayAccess(TSourceLoc, TIntermTyped* base);
+    void checkInputArrayConsistency(TSourceLoc, bool tailOnly = false);
+    void checkInputArrayConsistency(TSourceLoc, TLayoutGeometry, TType&, const TString&);
     TIntermTyped* handleDotDereference(TSourceLoc, TIntermTyped* base, TString& field);
     TFunction* handleFunctionDeclarator(TSourceLoc loc, TFunction& function);
     TIntermAggregate* handleFunctionPrototype(TSourceLoc, TFunction&);
@@ -230,6 +235,40 @@ protected:
     bool anyIndexLimits;
     TVector<TIntermTyped*> needsIndexLimitationChecking;
     // TODO: desktop functionality: track use of gl_FragDepth before redeclaration
+
+    //
+    // Geometry shader input arrays:
+    //  - array sizing is based on input primitive and/or explicit size
+    //  - array sizing is retroactive
+    //  - built-in block redeclarations interact with this
+    //
+    // Design:
+    //  - use a per-context "resize-list", a list of entities whose array sizes
+    //    can be fixed; this is logically one list, but physically two:
+    //     * a list for nodes in the AST
+    //     * a list for symbols in the symbol table
+    //    this could be done a bit more simply, but this allows better error messages.
+    //
+    //  - the resize-list starts empty at beginning of user-shader compilation, it does
+    //    not have built-ins in it
+    //
+    //  - on built-in input array use: copy-up symbol and add both the symbol and
+    //    its use to resize-list
+    //
+    //  - on user-input array declaration: add it to the resize-list
+    //
+    //  - on block redeclaration: copy-up symbol and add it to the resize-list
+    //     * note, that appropriately gives an error if redeclaring a block that
+    //       was already used and hence already copied-up
+    //
+    //  - on seeing an input primitive-layout declaration, fix everything in the resize-list,
+    //    giving errors for mismatch
+    //
+    //  - on seeing an array size declaration, give errors on mismatch between it and previous
+    //    input primitive declarations
+    //
+    TVector<TIntermSymbol*> inputArrayNodeResizeList;
+    TVector<TSymbol*> inputArraySymbolResizeList;
 };
 
 } // end namespace glslang
diff --git a/glslang/MachineIndependent/SymbolTable.h b/glslang/MachineIndependent/SymbolTable.h
index 9da462678fe3da6196f80be015281dbea7875660..b71d62cdd1fd05b85279d4bcbc6e34bb4b104f50 100644
--- a/glslang/MachineIndependent/SymbolTable.h
+++ b/glslang/MachineIndependent/SymbolTable.h
@@ -99,7 +99,7 @@ public:
     virtual int getUniqueId() const { return uniqueId; }
     virtual void dump(TInfoSink &infoSink) const = 0;
 
-    virtual bool isReadOnly() { return ! writable; }
+    virtual bool isReadOnly() const { return ! writable; }
     virtual void makeReadOnly() { writable = false; }
 
 protected:
@@ -417,9 +417,10 @@ public:
     //   3: user-shader globals
     //
 protected:
+    static const int globalLevel = 3;
     bool isSharedLevel(int level)  { return level <= 1; }    // exclude all per-compile levels
     bool isBuiltInLevel(int level) { return level <= 2; }    // exclude user globals
-    bool isGlobalLevel(int level)  { return level <= 3; }    // include user globals
+    bool isGlobalLevel(int level)  { return level <= globalLevel; }    // include user globals
 public:
     bool isEmpty() { return table.size() == 0; }
     bool atBuiltInLevel() { return isBuiltInLevel(currentLevel()); }
@@ -482,7 +483,7 @@ public:
     TSymbol* copyUp(TSymbol* shared)
     {
         TSymbol* copy = copyUpDeferredInsert(shared);
-        table[currentLevel()]->insert(*copy);
+        table[globalLevel]->insert(*copy);
         if (shared->getAsVariable())
             return copy;
         else {