From 8de7e7bf1483adf2047870543ca4b9d00b99fc8a Mon Sep 17 00:00:00 2001
From: John Kessenich <cepheus@frii.com>
Date: Sun, 4 Jun 2017 13:05:50 -0600
Subject: [PATCH] GLSL: Error when using location on an arrayed block.

This implements a recent change to the GLSL specification to enforce
this ill-defined situation.
---
 Test/450.frag                              |  9 +++++++++
 Test/450.tesc                              |  9 +++++++++
 Test/baseResults/450.frag.out              | 11 +++++++++--
 Test/baseResults/450.tesc.out              | 11 +++++++++--
 glslang/MachineIndependent/ParseHelper.cpp | 18 ++++++++++++++++++
 glslang/MachineIndependent/ParseHelper.h   |  1 +
 6 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/Test/450.frag b/Test/450.frag
index 04f3aa1ca..19772552d 100644
--- a/Test/450.frag
+++ b/Test/450.frag
@@ -54,3 +54,12 @@ float cull(int i)
 {
     return (i >= 6) ? gl_CullDistance[5] : gl_CullDistance[i];
 }
+
+layout(location = 6) in bName1 {
+    float f;
+    layout(location = 7) float g;
+} bInst1;
+layout(location = 8) in bName2 {
+    float f;
+    layout(location = 9) float g;  // ERROR, location on array
+} bInst2[3];
diff --git a/Test/450.tesc b/Test/450.tesc
index 75a9bf469..bf5c08373 100644
--- a/Test/450.tesc
+++ b/Test/450.tesc
@@ -12,3 +12,12 @@ void main()
 {
     gl_out[gl_InvocationID].gl_CullDistance[2] = gl_in[1].gl_CullDistance[2];
 }
+
+layout(location = 4) out bName1 {
+    float f;
+    layout(location = 5) float g;
+} bInst1[2];
+layout(location = 6) out bName2 {
+    float f;
+    layout(location = 7) float g;  // ERROR, location on array
+} bInst2[2][3];
diff --git a/Test/baseResults/450.frag.out b/Test/baseResults/450.frag.out
index 297ae63fb..3e4ed5f96 100644
--- a/Test/baseResults/450.frag.out
+++ b/Test/baseResults/450.frag.out
@@ -1,8 +1,11 @@
 450.frag
 Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.
+ERROR: 0:62: 'location' : cannot use in a block array where new locations are needed for each block element 
+ERROR: 1 compilation errors.  No code generated.
+
 
 Shader version: 450
-0:? Sequence
+ERROR: node is still EOpNull!
 0:8  Function Definition: main( ( global void)
 0:8    Function Parameters: 
 0:10    Sequence
@@ -160,13 +163,15 @@ Shader version: 450
 0:?     'us2dmsa' ( uniform usampler2DMSArray)
 0:?     'ii2dms' (layout( rgba32i) uniform iimage2DMS)
 0:?     'i2dmsa' (layout( rgba32f) uniform image2DMSArray)
+0:?     'bInst1' ( in block{layout( location=6 component=0) in float f, layout( location=7) in float g})
+0:?     'bInst2' ( in 3-element array of block{layout( location=8 component=0) in float f, layout( location=9) in float g})
 
 
 Linked fragment stage:
 
 
 Shader version: 450
-0:? Sequence
+ERROR: node is still EOpNull!
 0:8  Function Definition: main( ( global void)
 0:8    Function Parameters: 
 0:10    Sequence
@@ -273,4 +278,6 @@ Shader version: 450
 0:?     'us2dmsa' ( uniform usampler2DMSArray)
 0:?     'ii2dms' (layout( rgba32i) uniform iimage2DMS)
 0:?     'i2dmsa' (layout( rgba32f) uniform image2DMSArray)
+0:?     'bInst1' ( in block{layout( location=6 component=0) in float f, layout( location=7) in float g})
+0:?     'bInst2' ( in 3-element array of block{layout( location=8 component=0) in float f, layout( location=9) in float g})
 
diff --git a/Test/baseResults/450.tesc.out b/Test/baseResults/450.tesc.out
index 29da425ec..7e0918f6f 100644
--- a/Test/baseResults/450.tesc.out
+++ b/Test/baseResults/450.tesc.out
@@ -1,9 +1,12 @@
 450.tesc
 Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.
+ERROR: 0:20: 'location' : cannot use in a block array where new locations are needed for each block element 
+ERROR: 1 compilation errors.  No code generated.
+
 
 Shader version: 450
 vertices = -1
-0:? Sequence
+ERROR: node is still EOpNull!
 0:11  Function Definition: main( ( global void)
 0:11    Function Parameters: 
 0:13    Sequence
@@ -30,6 +33,8 @@ vertices = -1
 0:?   Linker Objects
 0:?     'gl_in' ( in 32-element array of block{ in 3-element array of float CullDistance gl_CullDistance})
 0:?     'gl_out' ( out 4-element array of block{ out 3-element array of float CullDistance gl_CullDistance})
+0:?     'bInst1' ( out 2-element array of block{layout( location=4 component=0) out float f, layout( location=5) out float g})
+0:?     'bInst2' ( out 2-element array of 3-element array of block{layout( location=6 component=0) out float f, layout( location=7) out float g})
 
 
 Linked tessellation control stage:
@@ -38,7 +43,7 @@ ERROR: Linking tessellation control stage: At least one shader must specify an o
 
 Shader version: 450
 vertices = -1
-0:? Sequence
+ERROR: node is still EOpNull!
 0:11  Function Definition: main( ( global void)
 0:11    Function Parameters: 
 0:13    Sequence
@@ -65,4 +70,6 @@ vertices = -1
 0:?   Linker Objects
 0:?     'gl_in' ( in 32-element array of block{ in 3-element array of float CullDistance gl_CullDistance})
 0:?     'gl_out' ( out 4-element array of block{ out 3-element array of float CullDistance gl_CullDistance})
+0:?     'bInst1' ( out 2-element array of block{layout( location=4 component=0) out float f, layout( location=5) out float g})
+0:?     'bInst2' ( out 2-element array of 3-element array of block{layout( location=6 component=0) out float f, layout( location=7) out float g})
 
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 91b14adff..5446a789f 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -4391,6 +4391,22 @@ void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symb
     }
 }
 
+// "For some blocks declared as arrays, the location can only be applied at the block level:
+// When a block is declared as an array where additional locations are needed for each member
+// for each block array element, it is a compile-time error to specify locations on the block
+// members.  That is, when locations would be under specified by applying them on block members,
+// they are not allowed on block members.  For arrayed interfaces (those generally having an
+// extra level of arrayness due to interface expansion), the outer array is stripped before
+// applying this rule."
+void TParseContext::layoutMemberLocationArrayCheck(const TSourceLoc& loc, bool memberWithLocation, TArraySizes* arraySizes)
+{
+    if (memberWithLocation && arraySizes != nullptr) {
+        if (arraySizes->getNumDims() > (currentBlockQualifier.isArrayedIo(language) ? 1 : 0))
+            error(loc, "cannot use in a block array where new locations are needed for each block element",
+                       "location", "");
+    }
+}
+
 // Do layout error checking with respect to a type.
 void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
 {
@@ -5693,6 +5709,8 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
         memberQualifier = newMemberQualification;
     }
 
+    layoutMemberLocationArrayCheck(loc, memberWithLocation, arraySizes);
+
     // Process the members
     fixBlockLocations(loc, currentBlockQualifier, typeList, memberWithLocation, memberWithoutLocation);
     fixBlockXfbOffsets(currentBlockQualifier, typeList);
diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h
index dc9dc6a04..17acf5d78 100644
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -338,6 +338,7 @@ public:
     void setLayoutQualifier(const TSourceLoc&, TPublicType&, TString&, const TIntermTyped*);
     void mergeObjectLayoutQualifiers(TQualifier& dest, const TQualifier& src, bool inheritOnly);
     void layoutObjectCheck(const TSourceLoc&, const TSymbol&);
+    void layoutMemberLocationArrayCheck(const TSourceLoc&, bool memberWithLocation, TArraySizes* arraySizes);
     void layoutTypeCheck(const TSourceLoc&, const TType&);
     void layoutQualifierCheck(const TSourceLoc&, const TQualifier&);
     void checkNoShaderLayouts(const TSourceLoc&, const TShaderQualifiers&);
-- 
GitLab