Do qualifier-based checking independent of declaring a variable.  Bug 11903.


git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@28502 e7fa87d3-cd2b-0410-9028-fcbf551c1848
diff --git a/Test/100.frag b/Test/100.frag
index 672e969..ddf7ba0 100644
--- a/Test/100.frag
+++ b/Test/100.frag
@@ -46,7 +46,7 @@
 float f13;

 invariant f13;           // ERROR

 struct S { int a; };

-invariant S;

+invariant S;             // ERROR, not an input or output

 invariant float fi;      // ERROR

 varying vec4 av;

 invariant av;            // okay in v100

@@ -194,4 +194,6 @@
     a.method(); // ERROR

 }

 

+#pragma STDGL invariant(all)

+

 uniform samplerExternalOES badExt;  // syntax ERROR

diff --git a/Test/300.frag b/Test/300.frag
index 28e030a..ff2da1f 100644
--- a/Test/300.frag
+++ b/Test/300.frag
@@ -153,5 +153,9 @@
 #error missing GL_FRAGMENT_PRECISION_HIGH
 #endif
 
+invariant in;                // ERROR
+invariant in vec4;           // ERROR
+invariant in vec4 fooinv;    // ERROR
+
 float imageBuffer;    // ERROR, reserved
 float uimage2DRect;   // ERROR, reserved
diff --git a/Test/baseResults/100.frag.out b/Test/baseResults/100.frag.out
index c3a0402..e4a5b7a 100644
--- a/Test/baseResults/100.frag.out
+++ b/Test/baseResults/100.frag.out
@@ -23,26 +23,31 @@
 ERROR: 0:40: 'switch' : Reserved word. 

 ERROR: 0:40: 'switch statements' : not supported for this version or the enabled extensions 

 ERROR: 0:45: '' : array size required 

-ERROR: 0:47: 'invariant' : can only apply to an output or an input in a non-vertex stage

+ERROR: 0:47: 'invariant' : can only apply to an output, or to an input in a non-vertex stage

  

-ERROR: 0:50: 'invariant' : can only apply to an output or an input in a non-vertex stage

+ERROR: 0:49: 'invariant' : can only apply to an output, or to an input in a non-vertex stage

+ 

+ERROR: 0:50: 'invariant' : can only apply to an output, or to an input in a non-vertex stage

  

 ERROR: 0:56: 'invariant' : not allowed in nested scope 

-ERROR: 0:56: 'invariant' : can only apply to an output or an input in a non-vertex stage

+ERROR: 0:56: 'invariant' : can only apply to an output, or to an input in a non-vertex stage

  

 ERROR: 0:57: 'invariant' : not allowed in nested scope 

-ERROR: 0:57: 'invariant' : can only apply to an output or an input in a non-vertex stage

+ERROR: 0:57: 'invariant' : can only apply to an output, or to an input in a non-vertex stage

  

 ERROR: 0:59: 'invariant' : not allowed in nested scope 

-ERROR: 0:59: 'invariant' : can only apply to an output or an input in a non-vertex stage

+ERROR: 0:59: 'invariant' : can only apply to an output, or to an input in a non-vertex stage

  

-ERROR: 0:63: 'invariant' : can only apply to an output or an input in a non-vertex stage

+ERROR: 0:63: 'invariant' : can only apply to an output, or to an input in a non-vertex stage

  

-ERROR: 0:64: 'invariant' : can only apply to an output or an input in a non-vertex stage

+ERROR: 0:64: 'invariant' : can only apply to an output, or to an input in a non-vertex stage

  

 ERROR: 0:66: 'sampler2D' : sampler/image types can only be used in uniform variables or function parameters: glob2D

 ERROR: 0:69: 'sampler2D' : sampler/image types can only be used in uniform variables or function parameters: v2D

 ERROR: 0:71: 'sampler2D' : sampler/image types can only be used in uniform variables or function parameters: vary2D

+ERROR: 0:75: 'in for stage inputs' : not supported for this version or the enabled extensions 

+ERROR: 0:77: 'invariant' : can only apply to an output, or to an input in a non-vertex stage

+ 

 ERROR: 0:75: 'g' : cannot use storage or interpolation qualifiers on structure members 

 ERROR: 0:76: 'h' : cannot use storage or interpolation qualifiers on structure members 

 ERROR: 0:77: 'i' : cannot use invariant qualifier on structure members 

@@ -77,8 +82,8 @@
 ERROR: 0:193: '.length' : not supported for this version or the enabled extensions 

 ERROR: 0:194: '.' : cannot apply to an array: method

 ERROR: 0:194: 'a' : can't use function syntax on variable 

-ERROR: 0:197: '' :  syntax error

-ERROR: 72 compilation errors.  No code generated.

+ERROR: 0:199: '' :  syntax error

+ERROR: 75 compilation errors.  No code generated.

 

 

 Shader version: 100

diff --git a/Test/baseResults/300.frag.out b/Test/baseResults/300.frag.out
index 5e33407..cbaa7c4 100644
--- a/Test/baseResults/300.frag.out
+++ b/Test/baseResults/300.frag.out
@@ -36,9 +36,12 @@
 ERROR: 0:129: 'texel offset' : value is out of range: [gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]

 ERROR: 0:148: 'qualifier' : cannot use auxiliary, memory, interpolation, or precision qualifier in a default qualifier declaration (declaration with no type) 

 ERROR: 0:150: 'early_fragment_tests' : not supported for this version or the enabled extensions 

-ERROR: 0:156: 'imageBuffer' : Reserved word. 

-ERROR: 0:156: '' :  syntax error

-ERROR: 39 compilation errors.  No code generated.

+ERROR: 0:156: 'invariant' : can only apply to an output 

+ERROR: 0:157: 'invariant' : can only apply to an output 

+ERROR: 0:158: 'invariant' : can only apply to an output 

+ERROR: 0:160: 'imageBuffer' : Reserved word. 

+ERROR: 0:160: '' :  syntax error

+ERROR: 42 compilation errors.  No code generated.

 

 

 Shader version: 300

@@ -390,6 +393,7 @@
 0:?     'colors' (out 4-element array of lowp 4-component vector of float)

 0:?     'st1' (uniform structure{mediump int i, lowp sampler2D s})

 0:?     'st2' (uniform structure{mediump int i, lowp sampler2D s})

+0:?     'fooinv' (invariant smooth in lowp 4-component vector of float)

 

 

 Linked fragment stage:

@@ -745,4 +749,5 @@
 0:?     'colors' (out 4-element array of lowp 4-component vector of float)

 0:?     'st1' (uniform structure{mediump int i, lowp sampler2D s})

 0:?     'st2' (uniform structure{mediump int i, lowp sampler2D s})

+0:?     'fooinv' (invariant smooth in lowp 4-component vector of float)

 

diff --git a/Test/baseResults/300.vert.out b/Test/baseResults/300.vert.out
index 87f630e..f27a399 100644
--- a/Test/baseResults/300.vert.out
+++ b/Test/baseResults/300.vert.out
@@ -20,7 +20,7 @@
 ERROR: 0:65: 'implicitly-sized array in a block' : not supported with this profile: es

 ERROR: 0:67: '' : array size required 

 ERROR: 0:76: 'invariant' : cannot change qualification after use 

-ERROR: 0:78: 'invariant' : can only apply to an output: invIn

+ERROR: 0:78: 'invariant' : can only apply to an output 

 ERROR: 0:88: 'ub2' : Cannot reuse block name within the same interface: uniform

 ERROR: 0:92: 'ub2' : Cannot reuse block name within the same interface: uniform

 ERROR: 0:96: 'ub2' : Cannot reuse block name within the same interface: uniform

diff --git a/Test/baseResults/430.vert.out b/Test/baseResults/430.vert.out
index b3cb9b2..5f1c35c 100644
--- a/Test/baseResults/430.vert.out
+++ b/Test/baseResults/430.vert.out
@@ -4,6 +4,7 @@
 ERROR: 0:7: 'in' : cannot declare an input block in a vertex shader 

 ERROR: 0:7: 'location qualifier on in/out block' : not supported for this version or the enabled extensions 

 ERROR: 0:8: 'location qualifier on in/out block' : not supported for this version or the enabled extensions 

+ERROR: 0:23: 'invariant' : can only apply to an output 

 ERROR: 0:21: 'g' : cannot use storage or interpolation qualifiers on structure members 

 ERROR: 0:22: 'h' : cannot use storage or interpolation qualifiers on structure members 

 ERROR: 0:23: 'i' : cannot use invariant qualifier on structure members 

@@ -58,7 +59,7 @@
 ERROR: 0:169: 'textureSamples and imageSamples' : not supported for this version or the enabled extensions 

 ERROR: 0:170: 'textureSamples and imageSamples' : not supported for this version or the enabled extensions 

 ERROR: 0:171: 'textureSamples and imageSamples' : not supported for this version or the enabled extensions 

-ERROR: 58 compilation errors.  No code generated.

+ERROR: 59 compilation errors.  No code generated.

 

 

 Shader version: 430

diff --git a/Test/baseResults/specExamples.frag.out b/Test/baseResults/specExamples.frag.out
index 6dfa4b8..7da8523 100644
--- a/Test/baseResults/specExamples.frag.out
+++ b/Test/baseResults/specExamples.frag.out
@@ -4,7 +4,7 @@
 ERROR: 0:20: '' : numeric literal too big 

 ERROR: 0:21: '' : hexidecimal literal too big 

 ERROR: 0:37: 'view' : redefinition 

-ERROR: 0:63: 'invariant' : can only apply to an output: Color

+ERROR: 0:63: 'invariant' : can only apply to an output 

 ERROR: 0:68: 'lightPosition' : redefinition 

 ERROR: 0:75: 'Atten' : member storage qualifier cannot contradict block storage qualifier 

 ERROR: 0:87: 'Color' : redefinition 

diff --git a/Test/baseResults/switch.frag.out b/Test/baseResults/switch.frag.out
index 6df32d2..65650dd 100644
--- a/Test/baseResults/switch.frag.out
+++ b/Test/baseResults/switch.frag.out
@@ -1,7 +1,7 @@
 switch.frag

 ERROR: 0:11: 'switch' : condition must be a scalar integer expression 

 ERROR: 0:14: 'switch' : condition must be a scalar integer expression 

-WARNING: 0:21: 'switch' : last case/default label not be followed by statements 

+WARNING: 0:21: 'switch' : last case/default label not followed by statements 

 ERROR: 0:28: 'switch' : cannot have statements before first case/default label 

 ERROR: 0:43: 'default' : duplicate label 

 ERROR: 0:63: 'case' : duplicated value 

@@ -15,7 +15,7 @@
 ERROR: 0:119: 'case' : cannot appear outside switch statement 

 ERROR: 0:120: 'default' : cannot appear outside switch statement 

 ERROR: 0:126: 'onlyInSwitch' : undeclared identifier 

-WARNING: 0:128: 'switch' : last case/default label not be followed by statements 

+WARNING: 0:128: 'switch' : last case/default label not followed by statements 

 ERROR: 0:140: 'nestedX' : undeclared identifier 

 ERROR: 0:156: 'nestedZ' : undeclared identifier 

 ERROR: 17 compilation errors.  No code generated.

diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index affef6c..6510c8f 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -1983,10 +1983,11 @@
 }
 
 //
-// move from parameter/unknown qualifiers to pipeline in/out qualifiers
+// Check/fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level.
 //
-void TParseContext::pipeInOutFix(TSourceLoc loc, TQualifier& qualifier)
+void TParseContext::globalQualifierFixCheck(TSourceLoc loc, TQualifier& qualifier)
 {
+    // move from parameter/unknown qualifiers to pipeline in/out qualifiers
     switch (qualifier.storage) {
     case EvqIn:
         profileRequires(loc, ENoProfile, 130, 0, "in for stage inputs");
@@ -2005,9 +2006,14 @@
     default:
         break;
     }
+
+    invariantCheck(loc, qualifier);
 }
 
-void TParseContext::globalQualifierCheck(TSourceLoc loc, const TQualifier& qualifier, const TPublicType& publicType)
+//
+// Check a full qualifier and type (no variable yet) at global level.
+//
+void TParseContext::globalQualifierTypeCheck(TSourceLoc loc, const TQualifier& qualifier, const TPublicType& publicType)
 {
     if (! symbolTable.atGlobalLevel())
         return;
@@ -3598,7 +3604,7 @@
         error(loc, "image variables not declared 'writeonly' must have a format layout qualifier", "", "");
 }
 
-// Do layout error checking that can be done within a qualifier proper, not needing to know
+// Do layout error checking that can be done within a layout qualifier proper, not needing to know
 // if there are blocks, atomic counters, variables, etc.
 void TParseContext::layoutQualifierCheck(TSourceLoc loc, const TQualifier& qualifier)
 {
@@ -3896,7 +3902,6 @@
     else
         nonInitConstCheck(loc, identifier, type);
 
-    invariantCheck(loc, type, identifier);
     samplerCheck(loc, type, identifier);
     atomicUintCheck(loc, type, identifier);
 
@@ -4409,7 +4414,7 @@
         TType& memberType = *typeList[member].type;
         TQualifier& memberQualifier = memberType.getQualifier();
         TSourceLoc memberLoc = typeList[member].loc;
-        pipeInOutFix(memberLoc, memberQualifier);
+        globalQualifierFixCheck(memberLoc, memberQualifier);
         if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != currentBlockQualifier.storage)
             error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", memberType.getFieldName().c_str(), "");
         memberQualifier.storage = currentBlockQualifier.storage;
@@ -4750,7 +4755,7 @@
         if (intermediate.inIoAccessed(identifier))
             error(loc, "cannot change qualification after use", "invariant", "");
         symbol->getWritableType().getQualifier().invariant = true;
-        invariantCheck(loc, symbol->getType(), identifier);
+        invariantCheck(loc, symbol->getType().getQualifier());
     } else
         warn(loc, "unknown requalification", "", "");
 }
@@ -4761,19 +4766,19 @@
         addQualifierToExisting(loc, qualifier, *identifiers[i]);
 }
 
-void TParseContext::invariantCheck(TSourceLoc loc, const TType& type, const TString& identifier)
+void TParseContext::invariantCheck(TSourceLoc loc, const TQualifier& qualifier)
 {
-    if (! type.getQualifier().invariant)
+    if (! qualifier.invariant)
         return;
 
-    bool pipeOut = type.getQualifier().isPipeOutput();
-    bool pipeIn = type.getQualifier().isPipeInput();
+    bool pipeOut = qualifier.isPipeOutput();
+    bool pipeIn = qualifier.isPipeInput();
     if (version >= 300 || profile != EEsProfile && version >= 420) {
         if (! pipeOut)
-            error(loc, "can only apply to an output:", "invariant", identifier.c_str());
+            error(loc, "can only apply to an output", "invariant", "");
     } else {
         if ((language == EShLangVertex && pipeIn) || (! pipeOut && ! pipeIn))
-            error(loc, "can only apply to an output or an input in a non-vertex stage\n", "invariant", "");
+            error(loc, "can only apply to an output, or to an input in a non-vertex stage\n", "invariant", "");
     }
 }
 
@@ -5002,7 +5007,7 @@
         return expression;
 
     if (lastStatements == 0) {
-        warn(loc, "last case/default label not be followed by statements", "switch", "");
+        warn(loc, "last case/default label not followed by statements", "switch", "");
 
         return expression;
     }
diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h
index 5fc676d..c678e42 100644
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -130,8 +130,8 @@
     void boolCheck(TSourceLoc, const TPublicType&);
     void samplerCheck(TSourceLoc, const TType&, const TString& identifier);
     void atomicUintCheck(TSourceLoc, const TType&, const TString& identifier);
-    void pipeInOutFix(TSourceLoc, TQualifier&);
-    void globalQualifierCheck(TSourceLoc, const TQualifier&, const TPublicType&);
+    void globalQualifierFixCheck(TSourceLoc, TQualifier&);
+    void globalQualifierTypeCheck(TSourceLoc, const TQualifier&, const TPublicType&);
     bool structQualifierErrorCheck(TSourceLoc, const TPublicType& pType);
     void mergeQualifiers(TSourceLoc, TQualifier& dst, const TQualifier& src, bool force);
     void setDefaultPrecision(TSourceLoc, TPublicType&, TPrecisionQualifier);
@@ -180,7 +180,7 @@
     void fixBlockUniformOffsets(TSourceLoc, TQualifier&, TTypeList&);
     void addQualifierToExisting(TSourceLoc, TQualifier, const TString& identifier);
     void addQualifierToExisting(TSourceLoc, TQualifier, TIdentifierList&);
-    void invariantCheck(TSourceLoc, const TType&, const TString& identifier);
+    void invariantCheck(TSourceLoc, const TQualifier&);
     void updateStandaloneQualifierDefaults(TSourceLoc, const TPublicType&);
     void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode);
     TIntermNode* addSwitch(TSourceLoc, TIntermTyped* expression, TIntermAggregate* body);
diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y
index c336564..3ee28c3 100644
--- a/glslang/MachineIndependent/glslang.y
+++ b/glslang/MachineIndependent/glslang.y
@@ -696,18 +696,16 @@
         $$ = 0;

     }

     | type_qualifier SEMICOLON {

-        parseContext.pipeInOutFix($1.loc, $1.qualifier);

+        parseContext.globalQualifierFixCheck($1.loc, $1.qualifier);

         parseContext.updateStandaloneQualifierDefaults($1.loc, $1);

         $$ = 0;

     }

     | type_qualifier IDENTIFIER SEMICOLON {

-        parseContext.pipeInOutFix($1.loc, $1.qualifier);

         parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers);

         parseContext.addQualifierToExisting($1.loc, $1.qualifier, *$2.string);

         $$ = 0;

     }

     | type_qualifier IDENTIFIER identifier_list SEMICOLON {

-        parseContext.pipeInOutFix($1.loc, $1.qualifier);

         parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers);

         $3->push_back($2.string);

         parseContext.addQualifierToExisting($1.loc, $1.qualifier, *$3);

@@ -719,7 +717,7 @@
     : type_qualifier IDENTIFIER LEFT_BRACE { parseContext.nestedBlockCheck($1.loc); } struct_declaration_list RIGHT_BRACE {

         --parseContext.structNestingLevel;

         parseContext.blockName = $2.string;

-        parseContext.pipeInOutFix($1.loc, $1.qualifier);

+        parseContext.globalQualifierFixCheck($1.loc, $1.qualifier);

         parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers);

         parseContext.currentBlockQualifier = $1.qualifier;

         $$.loc = $1.loc;

@@ -943,7 +941,7 @@
     : type_specifier {

         $$ = $1;

 

-        parseContext.globalQualifierCheck($1.loc, $1.qualifier, $$);

+        parseContext.globalQualifierTypeCheck($1.loc, $1.qualifier, $$);

         if ($1.arraySizes) {

             parseContext.profileRequires($1.loc, ENoProfile, 120, GL_3DL_array_objects, "arrayed type");

             parseContext.profileRequires($1.loc, EEsProfile, 300, 0, "arrayed type");

@@ -952,8 +950,8 @@
         parseContext.precisionQualifierCheck($$.loc, $$);

     }

     | type_qualifier type_specifier  {

-        parseContext.pipeInOutFix($1.loc, $1.qualifier);

-        parseContext.globalQualifierCheck($1.loc, $1.qualifier, $2);

+        parseContext.globalQualifierFixCheck($1.loc, $1.qualifier);

+        parseContext.globalQualifierTypeCheck($1.loc, $1.qualifier, $2);

 

         if ($2.arraySizes) {

             parseContext.profileRequires($2.loc, ENoProfile, 120, GL_3DL_array_objects, "arrayed type");

@@ -1965,6 +1963,7 @@
         }

     }

     | type_qualifier type_specifier struct_declarator_list SEMICOLON {

+        parseContext.globalQualifierFixCheck($1.loc, $1.qualifier);

         if ($2.arraySizes) {

             parseContext.profileRequires($2.loc, ENoProfile, 120, GL_3DL_array_objects, "arrayed type");

             parseContext.profileRequires($2.loc, EEsProfile, 300, 0, "arrayed type");