Add basic intra-stage linking validation for matching types and qualification of uniforms/ins/outs/globals, function body duplication, and mixing ES/non-ES shaders.  

Still need to handle arrays and built-in redeclarations, and many more rules, but this puts the basics in place.


git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23225 e7fa87d3-cd2b-0410-9028-fcbf551c1848
diff --git a/Test/baseResults/120.frag.out b/Test/baseResults/120.frag.out
index 49efdfc..bbcda69 100644
--- a/Test/baseResults/120.frag.out
+++ b/Test/baseResults/120.frag.out
@@ -281,9 +281,15 @@
 0:121          'gl_TexCoord' (smooth in unsized array of 4-component vector of float)

 0:121          3 (const int)

 0:?   Linker Objects

+0:?     'lowp' (float)

+0:?     'mediump' (float)

+0:?     'highp' (float)

+0:?     'precision' (float)

 0:?     'i' (smooth in 4-component vector of float)

 0:?     'o' (out 4-component vector of float)

 0:?     's2D' (uniform sampler2D)

 0:?     'centTexCoord' (centroid smooth in 2-component vector of float)

 0:?     'm' (uniform 4X2 matrix of float)

+0:?     'imageBuffer' (float)

+0:?     'uimage2DRect' (float)

 

diff --git a/Test/baseResults/300.vert.out b/Test/baseResults/300.vert.out
index 550b748..567be86 100644
--- a/Test/baseResults/300.vert.out
+++ b/Test/baseResults/300.vert.out
@@ -134,6 +134,7 @@
 0:?     'rep2' (centroid smooth sample out highp 4-component vector of float)

 0:?     'rep3' (in highp 4-component vector of float)

 0:?     's' (smooth out structure)

+0:?     'badsize2' (unsized array of highp float)

 0:?     'ubInst' (layout(shared ) uniform unsized array of block)

 0:?     'gl_VertexID' (gl_VertexId highp int)

 0:?     'gl_InstanceID' (gl_InstanceId highp int)

diff --git a/Test/baseResults/300BuiltIns.frag.out b/Test/baseResults/300BuiltIns.frag.out
index 0fb1a81..91b0218 100644
--- a/Test/baseResults/300BuiltIns.frag.out
+++ b/Test/baseResults/300BuiltIns.frag.out
@@ -181,4 +181,25 @@
 0:67          unpackHalf2x16 (mediump 2-component vector of float)

 0:67            'uy' (mediump uint)

 0:70      0.000000

+0:?   Linker Objects

+0:?     'imax' (mediump int)

+0:?     'imin' (mediump int)

+0:?     'umax' (mediump uint)

+0:?     'umin' (mediump uint)

+0:?     'x' (mediump 3-component vector of float)

+0:?     'y' (mediump 3-component vector of float)

+0:?     'bv' (3-component vector of bool)

+0:?     'uy' (mediump uint)

+0:?     'uv2c' (mediump 2-component vector of uint)

+0:?     'uv2y' (mediump 2-component vector of uint)

+0:?     'uv2x' (mediump 2-component vector of uint)

+0:?     'uv4y' (mediump 4-component vector of uint)

+0:?     'iv3a' (mediump 3-component vector of int)

+0:?     'iv3b' (mediump 3-component vector of int)

+0:?     'iv4a' (mediump 4-component vector of int)

+0:?     'iv4b' (mediump 4-component vector of int)

+0:?     'f' (mediump float)

+0:?     'v2a' (mediump 2-component vector of float)

+0:?     'v2b' (mediump 2-component vector of float)

+0:?     'v4' (mediump 4-component vector of float)

 

diff --git a/Test/baseResults/300operations.frag.out b/Test/baseResults/300operations.frag.out
index effb530..a679ca0 100644
--- a/Test/baseResults/300operations.frag.out
+++ b/Test/baseResults/300operations.frag.out
@@ -199,4 +199,5 @@
 0:127        'iv3' (mediump 3-component vector of int)

 0:?   Linker Objects

 0:?     'instanceName' (layout(shared ) uniform block)

+0:?     's' (structure)

 

diff --git a/Test/baseResults/300scope.vert.out b/Test/baseResults/300scope.vert.out
index 2eef9be..ba95ec3 100644
--- a/Test/baseResults/300scope.vert.out
+++ b/Test/baseResults/300scope.vert.out
@@ -90,6 +90,7 @@
 0:62          'S' (structure)

 0:62          0 (const int)

 0:?   Linker Objects

+0:?     'b' (bool)

 0:?     'gl_VertexID' (gl_VertexId highp int)

 0:?     'gl_InstanceID' (gl_InstanceId highp int)

 

diff --git a/Test/baseResults/400.geom.out b/Test/baseResults/400.geom.out
index edebc11..b32b57f 100644
--- a/Test/baseResults/400.geom.out
+++ b/Test/baseResults/400.geom.out
@@ -1,10 +1,12 @@
-0:3Function Definition: main( (void)

-0:3  Function Parameters: 

-0:5  Sequence

-0:5    EmitStreamVertex (void)

-0:5      1 (const int)

-0:6    EndStreamPrimitive (void)

-0:6      0 (const int)

-0:7    EmitVertex (void)

-0:8    EndPrimitive (void)

+0:? Sequence

+0:3  Function Definition: main( (void)

+0:3    Function Parameters: 

+0:5    Sequence

+0:5      EmitStreamVertex (void)

+0:5        1 (const int)

+0:6      EndStreamPrimitive (void)

+0:6        0 (const int)

+0:7      EmitVertex (void)

+0:8      EndPrimitive (void)

+0:?   Linker Objects

 

diff --git a/Test/baseResults/400.tesc.out b/Test/baseResults/400.tesc.out
index 04ce0e4..05a8a20 100644
--- a/Test/baseResults/400.tesc.out
+++ b/Test/baseResults/400.tesc.out
@@ -1,5 +1,7 @@
-0:3Function Definition: main( (void)

-0:3  Function Parameters: 

-0:5  Sequence

-0:5    Barrier (void)

+0:? Sequence

+0:3  Function Definition: main( (void)

+0:3    Function Parameters: 

+0:5    Sequence

+0:5      Barrier (void)

+0:?   Linker Objects

 

diff --git a/Test/baseResults/400.tese.out b/Test/baseResults/400.tese.out
index 7356a2d..67821cf 100644
--- a/Test/baseResults/400.tese.out
+++ b/Test/baseResults/400.tese.out
@@ -1,8 +1,10 @@
 ERROR: 0:5: 'barrier' : no matching overloaded function found 

 ERROR: 1 compilation errors.  No code generated.

 

-0:3Function Definition: main( (void)

-0:3  Function Parameters: 

-0:5  Sequence

-0:5    0.000000

+ERROR: node is still EOpNull!

+0:3  Function Definition: main( (void)

+0:3    Function Parameters: 

+0:5    Sequence

+0:5      0.000000

+0:?   Linker Objects

 

diff --git a/Test/baseResults/420.tese.out b/Test/baseResults/420.tese.out
index b7880b7..f44d24c 100644
--- a/Test/baseResults/420.tese.out
+++ b/Test/baseResults/420.tese.out
@@ -1,5 +1,7 @@
-0:3Function Definition: main( (void)

-0:3  Function Parameters: 

-0:5  Sequence

-0:5    MemoryBarrier (void)

+0:? Sequence

+0:3  Function Definition: main( (void)

+0:3    Function Parameters: 

+0:5    Sequence

+0:5      MemoryBarrier (void)

+0:?   Linker Objects

 

diff --git a/Test/baseResults/430.comp.out b/Test/baseResults/430.comp.out
index f160633..feac3c3 100644
--- a/Test/baseResults/430.comp.out
+++ b/Test/baseResults/430.comp.out
@@ -1,9 +1,11 @@
-0:3Function Definition: main( (void)

-0:3  Function Parameters: 

-0:5  Sequence

-0:5    MemoryBarrierAtomicCounter (void)

-0:6    MemoryBarrierBuffer (void)

-0:7    MemoryBarrierShared (void)

-0:8    MemoryBarrierImage (void)

-0:9    GroupMemoryBarrier (void)

+0:? Sequence

+0:3  Function Definition: main( (void)

+0:3    Function Parameters: 

+0:5    Sequence

+0:5      MemoryBarrierAtomicCounter (void)

+0:6      MemoryBarrierBuffer (void)

+0:7      MemoryBarrierShared (void)

+0:8      MemoryBarrierImage (void)

+0:9      GroupMemoryBarrier (void)

+0:?   Linker Objects

 

diff --git a/Test/baseResults/430scope.vert.out b/Test/baseResults/430scope.vert.out
index 540d52b..39d2556 100644
--- a/Test/baseResults/430scope.vert.out
+++ b/Test/baseResults/430scope.vert.out
@@ -86,6 +86,8 @@
 0:62          'S' (structure)

 0:62          0 (const int)

 0:?   Linker Objects

+0:?     'b' (bool)

+0:?     'tan' (float)

 0:?     'gl_VertexID' (gl_VertexId int)

 0:?     'gl_InstanceID' (gl_InstanceId int)

 

diff --git a/Test/baseResults/cppComplexExpr.vert.out b/Test/baseResults/cppComplexExpr.vert.out
index 36fb057..f6410bf 100644
--- a/Test/baseResults/cppComplexExpr.vert.out
+++ b/Test/baseResults/cppComplexExpr.vert.out
@@ -20,4 +20,5 @@
 0:39        'gl_Position' (gl_Position highp 4-component vector of float)

 0:39        Construct vec4 (highp 4-component vector of float)

 0:39          'sum' (highp float)

+0:?   Linker Objects

 

diff --git a/Test/baseResults/cppIndent.vert.out b/Test/baseResults/cppIndent.vert.out
index 7ae92d6..0f9f66a 100644
--- a/Test/baseResults/cppIndent.vert.out
+++ b/Test/baseResults/cppIndent.vert.out
@@ -25,4 +25,5 @@
 0:56        'gl_Position' (gl_Position 4-component vector of float)

 0:56        Construct vec4 (4-component vector of float)

 0:56          'sum' (float)

+0:?   Linker Objects

 

diff --git a/Test/baseResults/cppNest.vert.out b/Test/baseResults/cppNest.vert.out
index 1d33459..4574806 100644
--- a/Test/baseResults/cppNest.vert.out
+++ b/Test/baseResults/cppNest.vert.out
@@ -28,4 +28,5 @@
 0:86        'gl_Position' (gl_Position 4-component vector of float)

 0:86        Construct vec4 (4-component vector of float)

 0:86          'sum' (float)

+0:?   Linker Objects

 

diff --git a/Test/baseResults/cppSimple.vert.out b/Test/baseResults/cppSimple.vert.out
index 6dcdca3..b98f560 100644
--- a/Test/baseResults/cppSimple.vert.out
+++ b/Test/baseResults/cppSimple.vert.out
@@ -70,4 +70,6 @@
 0:130    move second child to first child (float)

 0:130      'twoPi' (float)

 0:130      6.280000

+0:?   Linker Objects

+0:?     'tod' (float)

 

diff --git a/Test/baseResults/dce.frag.out b/Test/baseResults/dce.frag.out
index d854aca..7975f99 100644
--- a/Test/baseResults/dce.frag.out
+++ b/Test/baseResults/dce.frag.out
@@ -113,4 +113,5 @@
 0:53        5 (const int)

 0:55      Pre-Increment (int)

 0:55        'c' (int)

+0:?   Linker Objects

 

diff --git a/Test/baseResults/errors.frag.out b/Test/baseResults/errors.frag.out
index 279ffd7..b555dd3 100644
--- a/Test/baseResults/errors.frag.out
+++ b/Test/baseResults/errors.frag.out
@@ -3,10 +3,12 @@
 ERROR: 0:1: 'int' :  main function cannot return a value

 ERROR: 2 compilation errors.  No code generated.

 

-0:1Function Definition: main(i1; (mediump int)

-0:1  Function Parameters: 

-0:1    'foo' (in mediump int)

-0:3  Sequence

-0:3    Branch: Return with expression

-0:3      1 (const int)

+ERROR: node is still EOpNull!

+0:1  Function Definition: main(i1; (mediump int)

+0:1    Function Parameters: 

+0:1      'foo' (in mediump int)

+0:3    Sequence

+0:3      Branch: Return with expression

+0:3        1 (const int)

+0:?   Linker Objects

 

diff --git a/Test/baseResults/functionSemantics.frag.out b/Test/baseResults/functionSemantics.frag.out
index 35af953..79c9b36 100644
--- a/Test/baseResults/functionSemantics.frag.out
+++ b/Test/baseResults/functionSemantics.frag.out
@@ -97,4 +97,5 @@
 0:35        Construct vec4 (mediump 4-component vector of float)

 0:35          Convert int to float (mediump float)

 0:35            'color' (mediump int)

+0:?   Linker Objects

 

diff --git a/Test/baseResults/length.frag.out b/Test/baseResults/length.frag.out
index bb8f8a6..5deccaa 100644
--- a/Test/baseResults/length.frag.out
+++ b/Test/baseResults/length.frag.out
@@ -18,4 +18,5 @@
 0:17        30.000000

 0:17        30.000000

 0:17        30.000000

+0:?   Linker Objects

 

diff --git a/Test/baseResults/lineContinuation.vert.out b/Test/baseResults/lineContinuation.vert.out
index 2e56483..b66a25f 100644
--- a/Test/baseResults/lineContinuation.vert.out
+++ b/Test/baseResults/lineContinuation.vert.out
@@ -12,6 +12,7 @@
 0:20        Construct vec4 (highp 4-component vector of float)

 0:20          'foo' (highp float)

 0:?   Linker Objects

+0:?     'foo' (highp float)

 0:?     'gl_VertexID' (gl_VertexId highp int)

 0:?     'gl_InstanceID' (gl_InstanceId highp int)

 

diff --git a/Test/baseResults/link1.frag.out b/Test/baseResults/link1.frag.out
new file mode 100644
index 0000000..5119acf
--- /dev/null
+++ b/Test/baseResults/link1.frag.out
@@ -0,0 +1,150 @@
+link1.frag

+

+0:? Sequence

+0:8  Sequence

+0:8    move second child to first child (4-component vector of float)

+0:8      'a' (4-component vector of float)

+0:8      vector-scale (4-component vector of float)

+0:8        8.000000

+0:8        'uv4' (uniform 4-component vector of float)

+0:13  Function Definition: main( (void)

+0:13    Function Parameters: 

+0:17  Sequence

+0:17    move second child to first child (4-component vector of float)

+0:17      'b' (4-component vector of float)

+0:17      vector-scale (4-component vector of float)

+0:17        8.000000

+0:17        'a' (4-component vector of float)

+0:19  Function Definition: foo(mf22; (2-component vector of int)

+0:19    Function Parameters: 

+0:19      'm' (in 2X2 matrix of float)

+0:21    Sequence

+0:21      Branch: Return with expression

+0:21        Convert float to int (2-component vector of int)

+0:21          direct index (in 2-component vector of float)

+0:21            'm' (in 2X2 matrix of float)

+0:21            0 (const int)

+0:24  Sequence

+0:24    move second child to first child (4-component vector of float)

+0:24      'c' (4-component vector of float)

+0:24      component-wise multiply (4-component vector of float)

+0:24        'b' (4-component vector of float)

+0:24        'b' (4-component vector of float)

+0:?   Linker Objects

+0:?     'uv4' (uniform 4-component vector of float)

+0:?     'glass' (uniform 3-component vector of float)

+0:?     'iv3' (smooth in 3-component vector of float)

+0:?     'cup' (smooth in 4-component vector of float)

+

+link2.frag

+

+0:? Sequence

+0:8  Sequence

+0:8    move second child to first child (4-component vector of float)

+0:8      'd' (4-component vector of float)

+0:8      vector-scale (4-component vector of float)

+0:8        8.000000

+0:8        'uv4' (uniform 4-component vector of float)

+0:13  Sequence

+0:13    move second child to first child (4-component vector of float)

+0:13      'e' (4-component vector of float)

+0:13      vector-scale (4-component vector of float)

+0:13        8.000000

+0:13        'd' (4-component vector of float)

+0:15  Function Definition: foo( (2-component vector of int)

+0:15    Function Parameters: 

+0:17    Sequence

+0:17      Branch: Return with expression

+0:17        2 (const int)

+0:17        2 (const int)

+0:20  Sequence

+0:20    move second child to first child (4-component vector of float)

+0:20      'f' (4-component vector of float)

+0:20      component-wise multiply (4-component vector of float)

+0:20        'e' (4-component vector of float)

+0:20        'e' (4-component vector of float)

+0:?   Linker Objects

+0:?     'uv4' (uniform 4-component vector of float)

+0:?     'glass' (uniform 2-component vector of float)

+0:?     'iv3' (smooth in 3-component vector of float)

+0:?     'cup' (flat in 4-component vector of float)

+

+link3.frag

+

+0:? Sequence

+0:?   Linker Objects

+0:?     'iv3' (smooth in highp 2-component vector of float)

+

+

+Linked fragment stage:

+

+ERROR: Linking fragment stage: Types must match:

+    glass: "uniform 3-component vector of float" versus "uniform 2-component vector of float"

+ERROR: Linking fragment stage: Interpolation and auxiliary storage qualifiers must match:

+    cup: "smooth in 4-component vector of float" versus "flat in 4-component vector of float"

+ERROR: Linking fragment stage: Cannot mix ES profile with non-ES profile shaders

+

+ERROR: Linking fragment stage: Types must match:

+ERROR: Linking fragment stage: Precision qualifiers must match:

+    iv3: "smooth in 3-component vector of float" versus "smooth in highp 2-component vector of float"

+

+0:? Sequence

+0:8  Sequence

+0:8    move second child to first child (4-component vector of float)

+0:8      'a' (4-component vector of float)

+0:8      vector-scale (4-component vector of float)

+0:8        8.000000

+0:8        'uv4' (uniform 4-component vector of float)

+0:13  Function Definition: main( (void)

+0:13    Function Parameters: 

+0:17  Sequence

+0:17    move second child to first child (4-component vector of float)

+0:17      'b' (4-component vector of float)

+0:17      vector-scale (4-component vector of float)

+0:17        8.000000

+0:17        'a' (4-component vector of float)

+0:19  Function Definition: foo(mf22; (2-component vector of int)

+0:19    Function Parameters: 

+0:19      'm' (in 2X2 matrix of float)

+0:21    Sequence

+0:21      Branch: Return with expression

+0:21        Convert float to int (2-component vector of int)

+0:21          direct index (in 2-component vector of float)

+0:21            'm' (in 2X2 matrix of float)

+0:21            0 (const int)

+0:24  Sequence

+0:24    move second child to first child (4-component vector of float)

+0:24      'c' (4-component vector of float)

+0:24      component-wise multiply (4-component vector of float)

+0:24        'b' (4-component vector of float)

+0:24        'b' (4-component vector of float)

+0:8  Sequence

+0:8    move second child to first child (4-component vector of float)

+0:8      'd' (4-component vector of float)

+0:8      vector-scale (4-component vector of float)

+0:8        8.000000

+0:8        'uv4' (uniform 4-component vector of float)

+0:13  Sequence

+0:13    move second child to first child (4-component vector of float)

+0:13      'e' (4-component vector of float)

+0:13      vector-scale (4-component vector of float)

+0:13        8.000000

+0:13        'd' (4-component vector of float)

+0:15  Function Definition: foo( (2-component vector of int)

+0:15    Function Parameters: 

+0:17    Sequence

+0:17      Branch: Return with expression

+0:17        2 (const int)

+0:17        2 (const int)

+0:20  Sequence

+0:20    move second child to first child (4-component vector of float)

+0:20      'f' (4-component vector of float)

+0:20      component-wise multiply (4-component vector of float)

+0:20        'e' (4-component vector of float)

+0:20        'e' (4-component vector of float)

+0:?   Linker Objects

+0:?     'uv4' (uniform 4-component vector of float)

+0:?     'glass' (uniform 3-component vector of float)

+0:?     'iv3' (smooth in 3-component vector of float)

+0:?     'cup' (smooth in 4-component vector of float)

+

diff --git a/Test/baseResults/mains1.frag.out b/Test/baseResults/mains1.frag.out
index 69a2078..9393d86 100644
--- a/Test/baseResults/mains1.frag.out
+++ b/Test/baseResults/mains1.frag.out
@@ -1,33 +1,54 @@
 mains1.frag

 

-0:3Function Definition: main( (void)

-0:3  Function Parameters: 

+0:? Sequence

+0:3  Function Definition: main( (void)

+0:3    Function Parameters: 

+0:?   Linker Objects

 

 mains2.frag

 

-0:3Function Definition: main( (void)

-0:3  Function Parameters: 

+0:? Sequence

+0:3  Function Definition: main( (void)

+0:3    Function Parameters: 

+0:?   Linker Objects

 

 noMain1.geom

 ERROR: #version: geometry shaders require non-es profile and version 150 or above

 ERROR: 1 compilation errors.  No code generated.

 

 

-0:3Function Definition: foo( (void)

-0:3  Function Parameters: 

+ERROR: node is still EOpNull!

+0:3  Function Definition: foo( (void)

+0:3    Function Parameters: 

+0:?   Linker Objects

 

 noMain2.geom

 

-0:3Function Definition: bar( (void)

-0:3  Function Parameters: 

+0:? Sequence

+0:3  Function Definition: bar( (void)

+0:3    Function Parameters: 

+0:?   Linker Objects

 

 

 Linked geometry stage:

 

-ERROR: Missing entry point: Each stage requires one "void main()" entry point

+ERROR: Linking geometry stage: Missing entry point: Each stage requires one "void main()" entry point

 

 Linked fragment stage:

 

-ERROR: Too many entry points: Each stage can have at most one "void main()" entry point.

+ERROR: Linking fragment stage: Multiple function bodies in multiple compilation units for the same signature in the same stage:

+    main(

 

+ERROR: node is still EOpNull!

+0:3  Function Definition: foo( (void)

+0:3    Function Parameters: 

+0:3  Function Definition: bar( (void)

+0:3    Function Parameters: 

+0:?   Linker Objects

+0:? Sequence

+0:3  Function Definition: main( (void)

+0:3    Function Parameters: 

+0:3  Function Definition: main( (void)

+0:3    Function Parameters: 

+0:?   Linker Objects

 

diff --git a/Test/baseResults/noMain.vert.out b/Test/baseResults/noMain.vert.out
index f55806c..fa97a7d 100644
--- a/Test/baseResults/noMain.vert.out
+++ b/Test/baseResults/noMain.vert.out
@@ -1,7 +1,11 @@
 noMain.vert

 

-0:3Function Definition: foo( (void)

-0:3  Function Parameters: 

+0:? Sequence

+0:3  Function Definition: foo( (void)

+0:3    Function Parameters: 

+0:?   Linker Objects

+0:?     'gl_VertexID' (gl_VertexId highp int)

+0:?     'gl_InstanceID' (gl_InstanceId highp int)

 

 mains.frag

 ERROR: 0:7: 'main' : function already has a body 

@@ -13,14 +17,14 @@
 0:3    Function Parameters: 

 0:7  Function Definition: main( (void)

 0:7    Function Parameters: 

+0:?   Linker Objects

 

 

 Linked vertex stage:

 

-ERROR: Missing entry point: Each stage requires one "void main()" entry point

+ERROR: Linking vertex stage: Missing entry point: Each stage requires one "void main()" entry point

 

 Linked fragment stage:

 

-ERROR: Too many entry points: Each stage can have at most one "void main()" entry point.

 

 

diff --git a/Test/baseResults/precision.frag.out b/Test/baseResults/precision.frag.out
index 76ef998..93f1cba 100644
--- a/Test/baseResults/precision.frag.out
+++ b/Test/baseResults/precision.frag.out
@@ -103,7 +103,10 @@
 0:69        0.200000

 0:?   Linker Objects

 0:?     'color' (smooth in mediump 3-component vector of float)

+0:?     'global_medium' (mediump int)

 0:?     'samplerLow' (uniform lowp sampler2D)

 0:?     'samplerMed' (uniform mediump sampler2D)

 0:?     'samplerHigh' (uniform highp sampler2D)

+0:?     'uint' (mediump 4-component vector of float)

+0:?     'global_high' (highp int)

 

diff --git a/Test/baseResults/prepost.frag.out b/Test/baseResults/prepost.frag.out
index bddbcae..f322cc7 100644
--- a/Test/baseResults/prepost.frag.out
+++ b/Test/baseResults/prepost.frag.out
@@ -1,112 +1,114 @@
-0:3Function Definition: main( (void)

-0:3  Function Parameters: 

-0:?   Sequence

-0:10    Sequence

-0:10      move second child to first child (int)

-0:10        'index' (int)

-0:10        5 (const int)

-0:12    move second child to first child (float)

-0:12      direct index (float)

-0:12        y: direct index for structure (5-element array of float)

-0:12          'str' (structure)

-0:12          0 (const int)

-0:12        4 (const int)

-0:12      2.000000

-0:13    move second child to first child (float)

-0:13      't' (float)

-0:13      Pre-Increment (float)

-0:13        indirect index (float)

-0:13          y: direct index for structure (5-element array of float)

-0:13            'str' (structure)

-0:13            0 (const int)

-0:13          Pre-Decrement (int)

-0:13            'index' (int)

-0:14    add second child into first child (float)

-0:14      direct index (float)

-0:14        y: direct index for structure (5-element array of float)

-0:14          'str' (structure)

-0:14          0 (const int)

-0:14        4 (const int)

-0:14      't' (float)

-0:15    move second child to first child (float)

-0:15      't' (float)

-0:15      Post-Decrement (float)

-0:15        direct index (float)

-0:15          y: direct index for structure (5-element array of float)

-0:15            'str' (structure)

-0:15            0 (const int)

-0:15          4 (const int)

-0:16    add second child into first child (float)

-0:16      indirect index (float)

-0:16        y: direct index for structure (5-element array of float)

-0:16          'str' (structure)

-0:16          0 (const int)

-0:16        Post-Increment (int)

-0:16          'index' (int)

-0:16      't' (float)

-0:17    Pre-Decrement (float)

-0:17      indirect index (float)

-0:17        y: direct index for structure (5-element array of float)

-0:17          'str' (structure)

-0:17          0 (const int)

-0:17        Pre-Decrement (int)

-0:17          'index' (int)

-0:19    Sequence

-0:19      move second child to first child (float)

-0:19        'x' (float)

-0:19        direct index (float)

-0:19          y: direct index for structure (5-element array of float)

-0:19            'str' (structure)

-0:19            0 (const int)

-0:19          4 (const int)

-0:20    Pre-Increment (float)

-0:20      'x' (float)

-0:21    Pre-Decrement (float)

-0:21      'x' (float)

-0:22    Post-Increment (float)

-0:22      'x' (float)

-0:23    Post-Decrement (float)

-0:23      'x' (float)

-0:27    Sequence

-0:27      move second child to first child (float)

-0:27        'y' (float)

-0:27        component-wise multiply (float)

-0:27          'x' (float)

-0:27          Pre-Increment (float)

+0:? Sequence

+0:3  Function Definition: main( (void)

+0:3    Function Parameters: 

+0:?     Sequence

+0:10      Sequence

+0:10        move second child to first child (int)

+0:10          'index' (int)

+0:10          5 (const int)

+0:12      move second child to first child (float)

+0:12        direct index (float)

+0:12          y: direct index for structure (5-element array of float)

+0:12            'str' (structure)

+0:12            0 (const int)

+0:12          4 (const int)

+0:12        2.000000

+0:13      move second child to first child (float)

+0:13        't' (float)

+0:13        Pre-Increment (float)

+0:13          indirect index (float)

+0:13            y: direct index for structure (5-element array of float)

+0:13              'str' (structure)

+0:13              0 (const int)

+0:13            Pre-Decrement (int)

+0:13              'index' (int)

+0:14      add second child into first child (float)

+0:14        direct index (float)

+0:14          y: direct index for structure (5-element array of float)

+0:14            'str' (structure)

+0:14            0 (const int)

+0:14          4 (const int)

+0:14        't' (float)

+0:15      move second child to first child (float)

+0:15        't' (float)

+0:15        Post-Decrement (float)

+0:15          direct index (float)

+0:15            y: direct index for structure (5-element array of float)

+0:15              'str' (structure)

+0:15              0 (const int)

+0:15            4 (const int)

+0:16      add second child into first child (float)

+0:16        indirect index (float)

+0:16          y: direct index for structure (5-element array of float)

+0:16            'str' (structure)

+0:16            0 (const int)

+0:16          Post-Increment (int)

+0:16            'index' (int)

+0:16        't' (float)

+0:17      Pre-Decrement (float)

+0:17        indirect index (float)

+0:17          y: direct index for structure (5-element array of float)

+0:17            'str' (structure)

+0:17            0 (const int)

+0:17          Pre-Decrement (int)

+0:17            'index' (int)

+0:19      Sequence

+0:19        move second child to first child (float)

+0:19          'x' (float)

+0:19          direct index (float)

+0:19            y: direct index for structure (5-element array of float)

+0:19              'str' (structure)

+0:19              0 (const int)

+0:19            4 (const int)

+0:20      Pre-Increment (float)

+0:20        'x' (float)

+0:21      Pre-Decrement (float)

+0:21        'x' (float)

+0:22      Post-Increment (float)

+0:22        'x' (float)

+0:23      Post-Decrement (float)

+0:23        'x' (float)

+0:27      Sequence

+0:27        move second child to first child (float)

+0:27          'y' (float)

+0:27          component-wise multiply (float)

 0:27            'x' (float)

-0:28    Sequence

-0:28      move second child to first child (float)

-0:28        'z' (float)

-0:28        component-wise multiply (float)

-0:28          'y' (float)

-0:28          Post-Decrement (float)

-0:28            'x' (float)

-0:33    Sequence

-0:33      move second child to first child (4-component vector of float)

-0:33        'v' (4-component vector of float)

-0:33        1.000000

-0:33        2.000000

-0:33        3.000000

-0:33        4.000000

-0:34    move second child to first child (float)

-0:34      direct index (float)

-0:34        'v' (4-component vector of float)

-0:34        1 (const int)

-0:34      Post-Decrement (float)

+0:27            Pre-Increment (float)

+0:27              'x' (float)

+0:28      Sequence

+0:28        move second child to first child (float)

+0:28          'z' (float)

+0:28          component-wise multiply (float)

+0:28            'y' (float)

+0:28            Post-Decrement (float)

+0:28              'x' (float)

+0:33      Sequence

+0:33        move second child to first child (4-component vector of float)

+0:33          'v' (4-component vector of float)

+0:33          1.000000

+0:33          2.000000

+0:33          3.000000

+0:33          4.000000

+0:34      move second child to first child (float)

 0:34        direct index (float)

 0:34          'v' (4-component vector of float)

-0:34          2 (const int)

-0:35    move second child to first child (float)

-0:35      direct index (float)

-0:35        'v' (4-component vector of float)

-0:35        0 (const int)

-0:35      Pre-Decrement (float)

+0:34          1 (const int)

+0:34        Post-Decrement (float)

+0:34          direct index (float)

+0:34            'v' (4-component vector of float)

+0:34            2 (const int)

+0:35      move second child to first child (float)

 0:35        direct index (float)

 0:35          'v' (4-component vector of float)

-0:35          3 (const int)

-0:37    move second child to first child (4-component vector of float)

-0:37      'gl_FragColor' (fragColor 4-component vector of float)

-0:37      vector-scale (4-component vector of float)

-0:37        'z' (float)

-0:37        'v' (4-component vector of float)

+0:35          0 (const int)

+0:35        Pre-Decrement (float)

+0:35          direct index (float)

+0:35            'v' (4-component vector of float)

+0:35            3 (const int)

+0:37      move second child to first child (4-component vector of float)

+0:37        'gl_FragColor' (fragColor 4-component vector of float)

+0:37        vector-scale (4-component vector of float)

+0:37          'z' (float)

+0:37          'v' (4-component vector of float)

+0:?   Linker Objects

 

diff --git a/Test/baseResults/specExamples.frag.out b/Test/baseResults/specExamples.frag.out
index 7c0558d..9bba530 100644
--- a/Test/baseResults/specExamples.frag.out
+++ b/Test/baseResults/specExamples.frag.out
@@ -196,6 +196,22 @@
 0:218            'c' (5-element array of float)

 0:218            'a' (5-element array of float)

 0:?   Linker Objects

+0:?     'fa' (float)

+0:?     'fc' (double)

+0:?     'texcoord1' (2-component vector of float)

+0:?     'texcoord2' (2-component vector of float)

+0:?     'position' (3-component vector of float)

+0:?     'myRGBA' (4-component vector of float)

+0:?     'textureLookup' (2-component vector of int)

+0:?     'less' (3-component vector of bool)

+0:?     'mat2D' (2X2 matrix of float)

+0:?     'optMatrix' (3X3 matrix of float)

+0:?     'view' (4X4 matrix of float)

+0:?     'projection' (4X4 matrix of float)

+0:?     'm' (3X2 matrix of float)

+0:?     'highPrecisionMVP' (4X4 matrix of double)

+0:?     'dm' (2X4 matrix of double)

+0:?     'lightVar' (structure)

 0:?     'normal' (smooth in 3-component vector of float)

 0:?     'TexCoord' (centroid smooth in 2-component vector of float)

 0:?     'Color' (invariant centroid smooth in 4-component vector of float)

diff --git a/Test/baseResults/syntaxError.frag.out b/Test/baseResults/syntaxError.frag.out
index 44892c2..54df813 100644
--- a/Test/baseResults/syntaxError.frag.out
+++ b/Test/baseResults/syntaxError.frag.out
@@ -2,4 +2,9 @@
 ERROR: 0:9: '' :  syntax error

 ERROR: 2 compilation errors.  No code generated.

 

+ERROR: node is still EOpNull!

+0:?   Linker Objects

+0:?     'bigColor' (uniform 4-component vector of float)

+0:?     'BaseColor' (smooth in 4-component vector of float)

+0:?     'd' (uniform float)

 

diff --git a/Test/baseResults/tokenLength.vert.out b/Test/baseResults/tokenLength.vert.out
index 7c42c8f..613a81c 100644
--- a/Test/baseResults/tokenLength.vert.out
+++ b/Test/baseResults/tokenLength.vert.out
@@ -77,6 +77,7 @@
 0:?   Linker Objects

 0:?     'BCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789' (in highp float)

 0:?     'ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789' (in highp float)

+0:?     'BCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789B' (highp float)

 0:?     'gl_VertexID' (gl_VertexId highp int)

 0:?     'gl_InstanceID' (gl_InstanceId highp int)

 

diff --git a/Test/link1.frag b/Test/link1.frag
new file mode 100644
index 0000000..3bb5cf6
--- /dev/null
+++ b/Test/link1.frag
@@ -0,0 +1,24 @@
+#version 130

+

+uniform vec4 uv4;

+uniform vec3 glass;

+

+const int ci = 8;

+

+vec4 a = ci * uv4;

+

+in vec3 iv3;

+in vec4 cup;

+

+void main()

+{

+}

+

+vec4 b = ci * a;

+

+ivec2 foo(mat2 m)

+{

+    return ivec2(m[0]);

+}

+

+vec4 c = b * b;

diff --git a/Test/link2.frag b/Test/link2.frag
new file mode 100644
index 0000000..e7fe630
--- /dev/null
+++ b/Test/link2.frag
@@ -0,0 +1,20 @@
+#version 130

+

+uniform vec4 uv4;

+uniform vec2 glass;

+

+const int ci = 8;

+

+vec4 d = ci * uv4;

+

+in vec3 iv3;

+flat in vec4 cup;

+

+vec4 e = ci * d;

+

+ivec2 foo()

+{

+    return ivec2(2);

+}

+

+vec4 f = e * e;

diff --git a/Test/link3.frag b/Test/link3.frag
new file mode 100644
index 0000000..a9604c4
--- /dev/null
+++ b/Test/link3.frag
@@ -0,0 +1,5 @@
+#version 300 es

+

+precision highp float;

+

+in vec2 iv3;

diff --git a/Test/runtests b/Test/runtests
index 16b5deb..55c039a 100644
--- a/Test/runtests
+++ b/Test/runtests
@@ -33,7 +33,8 @@
 }
 
 runLinkTest mains1.frag mains2.frag noMain1.geom noMain2.geom
-runLinkTest noMain.vert mains.frag 
+runLinkTest noMain.vert mains.frag
+runLinkTest link1.frag link2.frag link3.frag
 
 #
 # multi-threaded test
@@ -42,4 +43,3 @@
 $EXE -i *.vert *.geom *.frag *.tes* *.comp > singleThread.out
 $EXE -i *.vert *.geom *.frag *.tes* *.comp -t > multiThread.out
 diff singleThread.out multiThread.out
-
diff --git a/Todo.txt b/Todo.txt
index 4d4360b..84784b2 100644
--- a/Todo.txt
+++ b/Todo.txt
@@ -11,26 +11,29 @@
       - mixed es/non-es profiles
       - statically consumed input not produced by previous stage
       - matching between gl_PerVertex blocks and gl_PerFragment blocks
-      - compute shader not with other stages
+      - compute shader not combined with any other stages
+      - give error for sharing a packed block
       - 1.3: deprecated mixing fixed vertex/fragment stage with programmable fragment/vertex stage.
       - 4.3: remove cross-version linking restrictions.
       - 4.3: Allow mismatches in interpolation and auxiliary qualification across stages.
 	  - 4.4: A stage contains two different blocks, each with no instance name, where the blocks contain a member with the same name.
     Intra-stage linking
-      - exactly one main
-      - type consistency check of uniforms, globals, ins, and outs, both variables and blocks
+      + exactly one main
+      + type consistency check of uniforms, globals, ins, and outs
+        - still need to cover arrays and the combinations of this rule with redeclarations of built-ins
       - value checking of global const initializers
       - value checking of uniform initializers
-      - location/component/binding/index/offset match check
+      + location match
+      - component/binding/index/offset match check
       - location/component aliasing (except desktop vertex shader inputs)
       - location layout range/overlap semantics
       - geometry shader input array sizes and input layout qualifier declaration
       - compute shader layout(local_size_*) matching
-      - mixed es/non-es profiles
-      - matching initializers for globals
+      + mixed es/non-es profiles
       - recursion for both functions and subroutines
-          - Even the potential for recursion through subroutine uniforms is an error.
-      - matching redeclarations of interface blocks
+        - Even the potential for recursion through subroutine uniforms is an error.
+      - block matching
+        - matching redeclarations of interface blocks
       - read or write to both gl_ClipVertex and gl_ClipDistance
       - write to only one of gl_FragColor, gl_FragData, or user-declared
       - 4.3: Be clear that early_fragment_tests is only needed in one fragment-stage compilation unit.
diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp
index 62c93a4..20212c9 100644
--- a/glslang/MachineIndependent/Intermediate.cpp
+++ b/glslang/MachineIndependent/Intermediate.cpp
@@ -850,7 +850,7 @@
     return true;
 }
 
-void TIntermediate::addSymbolLinkageNodes(TIntermNode* root, TIntermAggregate*& linkage, EShLanguage language, TSymbolTable& symbolTable)
+void TIntermediate::addSymbolLinkageNodes(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
@@ -880,13 +880,9 @@
         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);
-    }
+    // Add a child to the root node for the linker objects    
+    linkage->setOperator(EOpLinkerObjects);
+    treeRoot = growAggregate(treeRoot, linkage);
 }
 
 void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable& symbolTable, const TString& name)
@@ -903,30 +899,179 @@
 }
 
 //
-// Merge the information in 'unit' into 'this'
+// Merge the information from 'unit' into 'this'
 //
-void TIntermediate::merge(TIntermediate& unit)
+void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
 {
     numMains += unit.numMains;
+
+    if (profile != EEsProfile && unit.profile == EEsProfile ||
+        profile == EEsProfile && unit.profile != EEsProfile)
+        error(infoSink, "Cannot mix ES profile with non-ES profile shaders\n");
+
+    if (unit.treeRoot == 0)
+        return;
+
+    if (treeRoot == 0) {
+        version = unit.version;
+        treeRoot = unit.treeRoot;
+        return;
+    } else
+        version = std::max(version, unit.version);
+
+    // Get the top-level globals of each level
+    TIntermSequence& globals = treeRoot->getAsAggregate()->getSequence();
+    TIntermSequence& unitGlobals = unit.treeRoot->getAsAggregate()->getSequence();
+
+    // Get the last members of the sequences, expected to be the linker-object lists
+    assert(globals.back()->getAsAggregate()->getOp() == EOpLinkerObjects);
+    assert(unitGlobals.back()->getAsAggregate()->getOp() == EOpLinkerObjects);
+    TIntermSequence& linkerObjects = globals.back()->getAsAggregate()->getSequence();
+    TIntermSequence& unitLinkerObjects = unitGlobals.back()->getAsAggregate()->getSequence();
+
+    mergeBodies(infoSink, globals, unitGlobals);
+    mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects);
+}
+
+//
+// Merge the function bodies and global-level initalizers from unitGlobals into globals.
+// Will error check duplication of function bodies for the same signature.
+//
+void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, const TIntermSequence& unitGlobals)
+{
+    // TODO: Performance: Processing in alphabetical order will be faster
+
+    // Error check the global objects, not including the linker objects
+    for (unsigned int child = 0; child < globals.size() - 1; ++child) {
+        for (unsigned int unitChild = 0; unitChild < unitGlobals.size() - 1; ++unitChild) {
+            TIntermAggregate* body = globals[child]->getAsAggregate();
+            TIntermAggregate* unitBody = unitGlobals[unitChild]->getAsAggregate();
+            if (body && unitBody && body->getOp() == EOpFunction && unitBody->getOp() == EOpFunction && body->getName() == unitBody->getName()) {
+                error(infoSink, "Multiple function bodies in multiple compilation units for the same signature in the same stage:");
+                infoSink.info << "    " << globals[child]->getAsAggregate()->getName() << "\n";
+            }
+        }
+    }
+
+    // Merge the global objects, just in front of the linker objects
+    globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1);
+}
+
+//
+// Merge the linker objects from unitLinkerObjects into linkerObjects.
+// Duplication is expected and filtered out, but contradictions are an error.
+//
+void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects)
+{
+    // Error check and merge the linker objects (duplicates should not be merged)
+    unsigned int initialNumLinkerObjects = linkerObjects.size();
+    for (unsigned int unitLinkObj = 0; unitLinkObj < unitLinkerObjects.size(); ++unitLinkObj) {
+        bool merge = true;
+        for (unsigned int linkObj = 0; linkObj < initialNumLinkerObjects; ++linkObj) {
+            TIntermSymbol* symbol = linkerObjects[linkObj]->getAsSymbolNode();
+            TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode();
+            assert(symbol && unitSymbol);
+            if (symbol->getName() == unitSymbol->getName()) {
+                // filter out copy
+                merge = false;
+                
+                // Check for consistent types/qualification/etc.
+                linkErrorCheck(infoSink, *symbol, *unitSymbol, false);
+            }
+        }
+        if (merge)
+            linkerObjects.push_back(unitLinkerObjects[unitLinkObj]);
+    }
 }
 
 void TIntermediate::errorCheck(TInfoSink& infoSink)
 {   
     if (numMains < 1)
         error(infoSink, "Missing entry point: Each stage requires one \"void main()\" entry point");
-    if (numMains > 1)
-        error(infoSink, "Too many entry points: Each stage can have at most one \"void main()\" entry point.");
 }
 
 void TIntermediate::error(TInfoSink& infoSink, const char* message)
 {
     infoSink.info.prefix(EPrefixError);
-    infoSink.info << message << "\n";
+    infoSink.info << "Linking " << StageName[language] << " stage: " << message << "\n";
 
     ++numErrors;
 }
 
 //
+// 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.
+//
+// This function only does one of intra- or cross-stage matching per call.
+//
+// TODO: Linker Functionality: this function is under active development
+//
+void TIntermediate::linkErrorCheck(TInfoSink& infoSink, const TIntermSymbol& symbol, const TIntermSymbol& unitSymbol, bool crossStage)
+{
+    bool writeTypeComparison = false;
+
+    // Types have to match
+    if (symbol.getType() != unitSymbol.getType()) {
+        error(infoSink, "Types must match:");
+        writeTypeComparison = true;
+    }
+
+    // Qualifiers have to (almost) match
+
+    // Storage...
+    if (symbol.getQualifier().storage != unitSymbol.getQualifier().storage) {
+        error(infoSink, "Storage qualifiers must match:");
+        writeTypeComparison = true;
+    }
+
+    // Precision...
+    if (symbol.getQualifier().precision != unitSymbol.getQualifier().precision) {
+        error(infoSink, "Precision qualifiers must match:");
+        writeTypeComparison = true;
+    }
+
+    // Invariance...
+    if (! crossStage && symbol.getQualifier().invariant != unitSymbol.getQualifier().invariant) {
+        error(infoSink, "Presence of invariant qualifier must match:");
+        writeTypeComparison = true;
+    }
+
+    // Auxiliary and interpolation...
+    if (symbol.getQualifier().centroid  != unitSymbol.getQualifier().centroid ||
+        symbol.getQualifier().smooth    != unitSymbol.getQualifier().smooth ||
+        symbol.getQualifier().flat      != unitSymbol.getQualifier().flat ||
+        symbol.getQualifier().sample    != unitSymbol.getQualifier().sample ||
+        symbol.getQualifier().patch     != unitSymbol.getQualifier().patch ||
+        symbol.getQualifier().nopersp   != unitSymbol.getQualifier().nopersp) {
+        error(infoSink, "Interpolation and auxiliary storage qualifiers must match:");
+        writeTypeComparison = true;
+    }
+
+    // Memory...
+    if (symbol.getQualifier().shared    != unitSymbol.getQualifier().shared ||
+        symbol.getQualifier().coherent  != unitSymbol.getQualifier().coherent ||
+        symbol.getQualifier().volatil   != unitSymbol.getQualifier().volatil ||
+        symbol.getQualifier().restrict  != unitSymbol.getQualifier().restrict ||
+        symbol.getQualifier().readonly  != unitSymbol.getQualifier().readonly ||
+        symbol.getQualifier().writeonly != unitSymbol.getQualifier().writeonly) {
+        error(infoSink, "Memory qualifiers must match:");
+        writeTypeComparison = true;
+    }
+
+    // Layouts...
+    if (symbol.getQualifier().layoutMatrix       != unitSymbol.getQualifier().layoutMatrix ||
+        symbol.getQualifier().layoutPacking      != unitSymbol.getQualifier().layoutPacking ||
+        symbol.getQualifier().layoutSlotLocation != unitSymbol.getQualifier().layoutSlotLocation) {
+        error(infoSink, "Layout qualification must match:");
+        writeTypeComparison = true;
+    }
+
+    if (writeTypeComparison)
+        infoSink.info << "    " << symbol.getName() << ": \"" << symbol.getType().getCompleteString() << "\" versus \"" <<
+                                                             unitSymbol.getType().getCompleteString() << "\"\n";
+}
+
+//
 // This deletes the tree.
 //
 void TIntermediate::removeTree()
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 25de8f9..d41a31d 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -51,12 +51,15 @@
             intermediate(interm), symbolTable(symt), infoSink(is), language(L),
             version(v), profile(p), forwardCompatible(fc), messages(m),    
             contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0),
-            linkage(0), tokensBeforeEOF(false),
+            tokensBeforeEOF(false),
             parsingBuiltins(pb), numErrors(0), afterEOF(false)
 {
     currentLoc.line = 1;
     currentLoc.string = 0;
 
+    // ensure we always have a linkage node, even if empty, to simplify tree topology algorithms
+    linkage = new TIntermAggregate;
+
     // set all precision defaults to EpqNone, which is correct for all desktop types
     // and for ES types that don't have defaults (thus getting an error on use)
     for (int type = 0; type < EbtNumTypes; ++type)
@@ -1795,7 +1798,7 @@
     //
     // Make the qualifier make sense.
     //
-    if (type.qualifier.storage  == EvqConst) {
+    if (type.qualifier.storage == EvqConst) {
         type.qualifier.storage = EvqTemporary;
         error(loc, "variables with qualifier 'const' must be initialized", identifier.c_str(), "");
     }
@@ -1808,8 +1811,10 @@
 void TParseContext::nonInitCheck(TSourceLoc loc, TString& identifier, TPublicType& publicType)
 {
     TType type(publicType);
-    bool newDeclaration;
+
+    bool newDeclaration;    // true if a new entry gets added to the symbol table
     TVariable* variable = redeclare(loc, identifier, type, newDeclaration);
+    
     if (! variable) {
         reservedErrorCheck(loc, identifier);
         variable = new TVariable(&identifier, type);
@@ -1823,19 +1828,19 @@
         voidErrorCheck(loc, identifier, publicType);
 
         // see if it's a linker-level object to track
-        if (type.getQualifier().isUniform() || type.getQualifier().isPipeInput() || type.getQualifier().isPipeOutput())
-                intermediate.addSymbolLinkageNode(linkage, *variable);
+        if (type.getQualifier().isUniform() || type.getQualifier().isPipeInput() || type.getQualifier().isPipeOutput() || type.getQualifier().storage == EvqGlobal)
+            intermediate.addSymbolLinkageNode(linkage, *variable);
     }
 }
 
 //
 // See if the identifier is a built-in symbol that can be redeclared,
 // and if so, copy of the symbol table's read-only built-in to the current
-// globol level, so it can be modified.
+// global level, so it can be modified.
 //
 TVariable* TParseContext::redeclare(TSourceLoc loc, const TString& identifier, const TType& type, bool& newDeclaration)
 {
-    newDeclaration = false;
+    newDeclaration = false;  // true if a new entry gets added to the symbol table
 
     if (profile == EEsProfile || identifier.substr(0, 3) != TString("gl_") || symbolTable.atBuiltInLevel())
         return 0;
diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp
index 7d7b75e..6b577c0 100644
--- a/glslang/MachineIndependent/ShaderLang.cpp
+++ b/glslang/MachineIndependent/ShaderLang.cpp
@@ -106,7 +106,7 @@
 bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, EShLanguage language, TInfoSink& infoSink, 
                            TSymbolTable& symbolTable)
 {
-    TIntermediate intermediate(version, profile);
+    TIntermediate intermediate(language, version, profile);
 	
     TParseContext parseContext(symbolTable, intermediate, true, version, profile, language, infoSink);
     TPpContext ppContext(parseContext);
@@ -452,7 +452,7 @@
     bool ret = parseContext.parseShaderStrings(ppContext, const_cast<char**>(shaderStrings), lengths, numStrings);
     if (! ret)
         success = false;
-    intermediate.addSymbolLinkageNodes(intermediate.getTreeRoot(), parseContext.linkage, parseContext.language, symbolTable);
+    intermediate.addSymbolLinkageNodes(parseContext.linkage, parseContext.language, symbolTable);
 
     // Clean up the symbol table. The AST is self-sufficient now.
     delete symbolTableMemory;
@@ -595,7 +595,7 @@
     compiler->infoSink.info.erase();
     compiler->infoSink.debug.erase();
 
-    TIntermediate intermediate;
+    TIntermediate intermediate(compiler->getLanguage());
     bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, optLevel, resources, defaultVersion, forwardCompatible, messages, intermediate);
 
     //
@@ -866,7 +866,7 @@
 {
     infoSink = new TInfoSink;
     compiler = new TDeferredCompiler(stage, *infoSink);
-    intermediate = new TIntermediate;
+    intermediate = new TIntermediate(s);
 }
 
 TShader::~TShader()
@@ -941,7 +941,7 @@
     if (stages[stage].size() == 1)
         merged = stages[stage].front()->intermediate;    
     else {
-        intermediate[stage] = new TIntermediate();
+        intermediate[stage] = new TIntermediate(stage);
         merged = intermediate[stage];
     }
 
@@ -950,7 +950,7 @@
     if (stages[stage].size() > 1) {
         std::list<TShader*>::const_iterator it;
         for (it = stages[stage].begin(); it != stages[stage].end(); ++it)
-            merged->merge(*(*it)->intermediate);
+            merged->merge(*infoSink, *(*it)->intermediate);
 
         if (messages & EShMsgAST)
             merged->outputTree(*infoSink);
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index e32b4fd..9b92244 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -56,7 +56,7 @@
 //
 class TIntermediate {
 public:
-    explicit TIntermediate(int v = 0, EProfile p = ENoProfile) : treeRoot(0), profile(p), version(v), numMains(0), numErrors(0) { }
+    explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) : language(l), treeRoot(0), profile(p), version(v), numMains(0), numErrors(0) { }
 
     void setVersion(int v) { version = v; }
     int getVersion() const { return version; }
@@ -95,20 +95,24 @@
     TIntermBranch* addBranch(TOperator, TIntermTyped*, TSourceLoc);
     TIntermTyped* addSwizzle(TVectorFields&, TSourceLoc);
     bool postProcess(TIntermNode*, EShLanguage);
-    void addSymbolLinkageNodes(TIntermNode* root, TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
+    void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
     void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
     void addSymbolLinkageNode(TIntermAggregate*& linkage, const TVariable&);
 
-    void merge(TIntermediate&);
-    void errorCheck(TInfoSink& infoSink);
+    void merge(TInfoSink&, TIntermediate&);
+    void errorCheck(TInfoSink&);
 
-    void outputTree(TInfoSink& infoSink);
+    void outputTree(TInfoSink&);
 	void removeTree();
 
 protected:
+    void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
+    void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
     void error(TInfoSink& infoSink, const char*);
+    void linkErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage);
 
 protected:
+    EShLanguage language;
     TIntermNode* treeRoot;
     EProfile profile;
     int version;