diff --git a/Install/Windows/glslangValidator.exe b/Install/Windows/glslangValidator.exe index 600014cd..6e5c328c 100644 Binary files a/Install/Windows/glslangValidator.exe and b/Install/Windows/glslangValidator.exe differ diff --git a/Test/100.frag b/Test/100.frag index 529b3600..61107c2b 100644 --- a/Test/100.frag +++ b/Test/100.frag @@ -43,3 +43,36 @@ void main() invariant gl_FragColor; float fa[]; // ERROR +float f13; +invariant f13; // ERROR +struct S { int a; }; +invariant S; +invariant float fi; // ERROR +varying vec4 av; +invariant av; // okay in v100 + +void foo10() +{ + invariant f; // ERROR + invariant float f2; // ERROR + float f3; + invariant f3; // ERROR +} + +uniform vec2 uv2; +invariant uv2; // ERROR +invariant uniform vec3 uv3; // ERROR + +sampler2D glob2D; // ERROR +void f11(sampler2D p2d) +{ + sampler2D v2D; // ERROR +} +varying sampler2D vary2D; // ERROR + +struct sp { + highp float f; + in float g; // ERROR + uniform float h; // ERROR + invariant float i; // ERROR +}; diff --git a/Test/300.frag b/Test/300.frag index d63c81e2..30343992 100644 --- a/Test/300.frag +++ b/Test/300.frag @@ -36,7 +36,7 @@ struct s { sampler2D s; }; -out s badout; // ERROR +in s badout; // ERROR, can't contain a sampler struct S2 { vec3 c; @@ -108,7 +108,19 @@ out vec4 colors[4]; void foo() { colors[2] = c4D; - colors[ic1D] = c4D; + colors[ic1D] = c4D; // ERROR +} + +uniform s st1; +uniform s st2; + +void foo13(s inSt2) +{ + if (st1 == st2); // ERROR + if (st1 != st2); // ERROR + st1.s == st2.s; // ERROR + inSt2 = st1; // ERROR + inSt2 == st1; // ERROR } float imageBuffer; // ERROR, reserved diff --git a/Test/300.vert b/Test/300.vert index 7f5f3268..01ececec 100644 --- a/Test/300.vert +++ b/Test/300.vert @@ -66,3 +66,17 @@ uniform ub { } ubInst[]; // ERROR void foo(int a[]); // ERROR float okayA[] = float[](3.0, 4.0); // Okay + +out vec3 newV; +void newVFun() +{ + newV = v3; +} + +invariant newV; // ERROR, variable already used +in vec4 invIn; +invariant invIn; // ERROR, in v300 +out S s2; +invariant s2; +invariant out S s3; +flat out int; diff --git a/Test/430.vert b/Test/430.vert index 54cf775a..6912fb4e 100644 --- a/Test/430.vert +++ b/Test/430.vert @@ -15,3 +15,19 @@ void foo() { gl_ClipDistance[2] = 3.7; } + +struct sp { + highp float f; + in float g; // ERROR + uniform float h; // ERROR + invariant float i; // ERROR + volatile float j; // ERROR + layout(row_major) mat3 m3; // ERROR +}; + +void foo3(invariant vec4 v4, // ERROR + volatile vec3 v3, + layout(location = 3) vec2 v2, // ERROR + centroid vec3 cv3) // ERROR +{ +} \ No newline at end of file diff --git a/Test/baseResults/100.frag.out b/Test/baseResults/100.frag.out index 5c376eba..8c7b64fa 100644 --- a/Test/baseResults/100.frag.out +++ b/Test/baseResults/100.frag.out @@ -20,7 +20,27 @@ ERROR: 0:38: 'array comparison' : not supported for this version or the enabled 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: 22 compilation errors. No code generated. +ERROR: 0:47: 'invariant' : can only apply to an output or 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:56: '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 an input in a non-vertex stage + +ERROR: 0:59: '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 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: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: '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 +ERROR: 35 compilation errors. No code generated. ERROR: node is still EOpNull! 0:3 Sequence @@ -96,6 +116,11 @@ ERROR: node is still EOpNull! 0:38 's2' (structure{f,a}) 0:38 true case is null 0:40 'b' (mediump int) +0:54 Function Definition: foo10( (void) +0:54 Function Parameters: +0:67 Function Definition: f11(s21; (void) +0:67 Function Parameters: +0:67 'p2d' (in lowp sampler2D) 0:? Linker Objects 0:? 'a' (3-element array of mediump int) 0:? 'uint' (mediump int) @@ -103,4 +128,11 @@ ERROR: node is still EOpNull! 0:? 'f' (mediump float) 0:? '__anon__0' (layout(column_major shared ) uniform block{x}) 0:? 'fa' (unsized array of mediump float) +0:? 'f13' (mediump float) +0:? 'fi' (invariant mediump float) +0:? 'av' (smooth in mediump 4-component vector of float) +0:? 'uv2' (uniform mediump 2-component vector of float) +0:? 'uv3' (invariant uniform mediump 3-component vector of float) +0:? 'glob2D' (lowp sampler2D) +0:? 'vary2D' (smooth in lowp sampler2D) diff --git a/Test/baseResults/300.frag.out b/Test/baseResults/300.frag.out index 2e0d6575..622033d0 100644 --- a/Test/baseResults/300.frag.out +++ b/Test/baseResults/300.frag.out @@ -1,8 +1,8 @@ ERROR: 0:30: 'noperspective' : Reserved word. ERROR: 0:30: 'noperspective' : not supported with this profile: es -ERROR: 0:31: 'sampler/image' : samplers and images must be uniform +ERROR: 0:31: 'sampler2D' : sampler/image types can only be used in uniform variables or function parameters: bads ERROR: 0:32: 'uint' : cannot apply precision statement to this type; use 'float', 'int' or a sampler type -ERROR: 0:39: 'structure' : samplers and images must be uniform (structure cannot contain a sampler or image) +ERROR: 0:39: 'structure' : non-uniform struct contains a sampler or image: badout ERROR: 0:69: 'variable indexing sampler array' : not supported with this profile: es ERROR: 0:83: 'double' : Reserved word. ERROR: 0:83: 'double' : not supported with this profile: es @@ -18,9 +18,15 @@ ERROR: 0:102: 'arrays of arrays' : not supported with this profile: es ERROR: 0:103: 'arrays of arrays' : not supported with this profile: es ERROR: 0:100: 'arrays of arrays' : not supported with this profile: es ERROR: 0:111: 'variable indexing fragment shader ouput array' : not supported with this profile: es -ERROR: 0:114: 'imageBuffer' : Reserved word. -ERROR: 0:114: '' : syntax error -ERROR: 22 compilation errors. No code generated. +ERROR: 0:119: '==' : can't use with samplers or structs containing samplers +ERROR: 0:120: '!=' : can't use with samplers or structs containing samplers +ERROR: 0:121: '==' : can't use with samplers or structs containing samplers +ERROR: 0:121: '==' : wrong operand types: no operation '==' exists that takes a left-hand operand of type 'lowp sampler2D' and a right operand of type 'lowp sampler2D' (or there is no acceptable conversion) +ERROR: 0:122: '=' : can't use with samplers or structs containing samplers +ERROR: 0:123: '==' : can't use with samplers or structs containing samplers +ERROR: 0:126: 'imageBuffer' : Reserved word. +ERROR: 0:126: '' : syntax error +ERROR: 28 compilation errors. No code generated. ERROR: node is still EOpNull! 0:53 Function Definition: main( (void) @@ -223,6 +229,30 @@ ERROR: node is still EOpNull! 0:111 'colors' (out 4-element array of lowp 4-component vector of float) 0:111 'ic1D' (flat in mediump int) 0:111 'c4D' (smooth lowp 4-component vector of float) +0:117 Function Definition: foo13(struct-s-i1-s211; (void) +0:117 Function Parameters: +0:117 'inSt2' (in structure{i,s}) +0:119 Sequence +0:119 Test condition and select (void) +0:119 Condition +0:119 Compare Equal (bool) +0:119 'st1' (uniform structure{i,s}) +0:119 'st2' (uniform structure{i,s}) +0:119 true case is null +0:120 Test condition and select (void) +0:120 Condition +0:120 Compare Not Equal (bool) +0:120 'st1' (uniform structure{i,s}) +0:120 'st2' (uniform structure{i,s}) +0:120 true case is null +0:121 Constant: +0:121 false (const bool) +0:122 move second child to first child (structure{i,s}) +0:122 'inSt2' (in structure{i,s}) +0:122 'st1' (uniform structure{i,s}) +0:123 Compare Equal (bool) +0:123 'inSt2' (in structure{i,s}) +0:123 'st1' (uniform structure{i,s}) 0:? Linker Objects 0:? 's2D' (uniform lowp sampler2D) 0:? 's3D' (uniform lowp sampler3D) @@ -249,11 +279,13 @@ ERROR: node is still EOpNull! 0:? 'ic4D' (flat in mediump 4-component vector of int) 0:? 'badv' (noperspective in lowp 4-component vector of float) 0:? 'bads' (smooth in lowp sampler2D) -0:? 'badout' (out structure{i,s}) +0:? 'badout' (smooth in structure{i,s}) 0:? 's2' (smooth in structure{c,f}) 0:? 'sc' (out lowp 3-component vector of float) 0:? 'sf' (out lowp float) 0:? 'arrayedSampler' (uniform 5-element array of lowp sampler2D) 0:? 'multiInst' (layout(column_major shared ) uniform 2-element array of block{a,b,c}) 0:? 'colors' (out 4-element array of lowp 4-component vector of float) +0:? 'st1' (uniform structure{i,s}) +0:? 'st2' (uniform structure{i,s}) diff --git a/Test/baseResults/300.vert.out b/Test/baseResults/300.vert.out index 38826088..8000c70f 100644 --- a/Test/baseResults/300.vert.out +++ b/Test/baseResults/300.vert.out @@ -18,7 +18,9 @@ ERROR: 0:63: '' : array size required ERROR: 0:65: '' : array size required ERROR: 0:64: '' : array size required ERROR: 0:67: '' : array size required -ERROR: 20 compilation errors. No code generated. +ERROR: 0:78: 'invariant' : can only apply to an output + invIn +ERROR: 21 compilation errors. No code generated. ERROR: node is still EOpNull! 0:27 Function Definition: main( (void) @@ -136,6 +138,12 @@ ERROR: node is still EOpNull! 0:68 Constant: 0:68 3.000000 0:68 4.000000 +0:71 Function Definition: newVFun( (void) +0:71 Function Parameters: +0:73 Sequence +0:73 move second child to first child (highp 3-component vector of float) +0:73 'newV' (smooth out highp 3-component vector of float) +0:73 'v3' (in highp 3-component vector of float) 0:? Linker Objects 0:? 'm43' (uniform highp 4X3 matrix of float) 0:? 'm33' (uniform highp 3X3 matrix of float) @@ -155,6 +163,10 @@ ERROR: node is still EOpNull! 0:? 'badsize2' (unsized array of highp float) 0:? 'ubInst' (layout(column_major shared ) uniform unsized array of block{a}) 0:? 'okayA' (2-element array of highp float) +0:? 'newV' (smooth out highp 3-component vector of float) +0:? 'invIn' (in highp 4-component vector of float) +0:? 's2' (smooth out structure{c,f}) +0:? 's3' (invariant smooth out structure{c,f}) 0:? 'gl_VertexID' (gl_VertexId highp int) 0:? 'gl_InstanceID' (gl_InstanceId highp int) diff --git a/Test/baseResults/430.vert.out b/Test/baseResults/430.vert.out index 166d0475..8500615f 100644 --- a/Test/baseResults/430.vert.out +++ b/Test/baseResults/430.vert.out @@ -2,7 +2,15 @@ Warning, version 430 is not yet complete; some version-specific features are pre ERROR: 0:3: 'v4' : location qualifiers only appy to uniform, buffer, in, or out storage qualifiers ERROR: 0:7: 'location qualifier on input block' : not supported for this version or the enabled extensions ERROR: 0:8: 'location qualifier on output block' : not supported for this version or the enabled extensions -ERROR: 3 compilation errors. No code generated. +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 +ERROR: 0:24: 'j' : cannot use memory qualifiers on structure members +ERROR: 0:25: 'm3' : cannot use layout qualifiers on structure members +ERROR: 0:28: '' : cannot use invariant qualifier on a function parameter +ERROR: 0:30: '' : cannot use layout qualifiers on a function parameter +ERROR: 0:31: '' : cannot use auxiliary or interpolation qualifiers on a function parameter +ERROR: 11 compilation errors. No code generated. ERROR: node is still EOpNull! 0:14 Function Definition: foo( (void) @@ -18,6 +26,12 @@ ERROR: node is still EOpNull! 0:16 2 (const int) 0:16 Constant: 0:16 3.700000 +0:31 Function Definition: foo3(vf4;vf3;vf2;vf3; (void) +0:31 Function Parameters: +0:31 'v4' (in 4-component vector of float) +0:31 'v3' (in 3-component vector of float) +0:31 'v2' (in 2-component vector of float) +0:31 'cv3' (in 3-component vector of float) 0:? Linker Objects 0:? 'v4' (layout(location=3 ) 4-component vector of float) 0:? 'uv4' (layout(location=3 ) uniform 4-component vector of float) diff --git a/Test/baseResults/specExamples.frag.out b/Test/baseResults/specExamples.frag.out index 19a1c155..f5afa450 100644 --- a/Test/baseResults/specExamples.frag.out +++ b/Test/baseResults/specExamples.frag.out @@ -3,6 +3,8 @@ ERROR: 0:6: '=' : cannot convert from 'const uint' to 'int' 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:68: 'lightPosition' : redefinition ERROR: 0:75: 'Atten' : member storage qualifier cannot contradict block storage qualifier ERROR: 0:87: 'Color' : redefinition @@ -46,7 +48,7 @@ ERROR: 0:226: 'in' : not allowed in nested scope ERROR: 0:227: 'in' : not allowed in nested scope ERROR: 0:228: 'in' : not allowed in nested scope ERROR: 0:232: 'out' : not allowed in nested scope -ERROR: 47 compilation errors. No code generated. +ERROR: 48 compilation errors. No code generated. gl_FragCoord pixel center is integer gl_FragCoord origin is upper left diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index 8edf8bd9..330df775 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -768,7 +768,7 @@ public: *p = 0; TString s(buf); - s.append(getCompleteTypeString()); + s.append(getBasicTypeString()); // Add struct/block members if (structure) { @@ -784,7 +784,7 @@ public: return s; } - TString getCompleteTypeString() const + TString getBasicTypeString() const { if (basicType == EbtSampler) return sampler.getString(); diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index d21d95dd..565abba2 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -415,7 +415,7 @@ TIntermTyped* TParseContext::handleVariable(TSourceLoc loc, TSymbol* symbol, TSt TType* type; if (variable->isReadOnly()) { type = new TType; - // break sharing with built-ins + // break type sharing with built-ins type->deepCopy(variable->getType()); // track use of unredeclared gl_FragCoord @@ -477,7 +477,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"); - else if (language == EShLangFragment && base->getQualifier().storage == EvqVaryingOut) + else if (language == EShLangFragment && base->getQualifier().isPipeOutput()) requireProfile(base->getLoc(), ~EEsProfile, "variable indexing fragment shader ouput array"); else if (base->getBasicType() == EbtSampler && version >= 130) { const char* explanation = "variable indexing sampler array"; @@ -720,7 +720,7 @@ TFunction* TParseContext::handleFunctionDeclarator(TSourceLoc loc, TFunction& fu const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0; if (prevDec) { if (prevDec->getType() != function.getType()) { - error(loc, "overloaded functions must have the same return type", function.getType().getCompleteTypeString().c_str(), ""); + error(loc, "overloaded functions must have the same return type", function.getType().getBasicTypeString().c_str(), ""); } for (int i = 0; i < prevDec->getParamCount(); ++i) { if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage) @@ -783,7 +783,7 @@ TIntermAggregate* TParseContext::handleFunctionPrototype(TSourceLoc loc, TFuncti if (function.getParamCount() > 0) error(loc, "function cannot take any parameter(s)", function.getName().c_str(), ""); if (function.getType().getBasicType() != EbtVoid) - error(loc, "", function.getType().getCompleteTypeString().c_str(), "main function cannot return a value"); + error(loc, "", function.getType().getBasicTypeString().c_str(), "main function cannot return a value"); intermediate.addMainCount(); } @@ -1495,23 +1495,15 @@ void TParseContext::boolCheck(TSourceLoc loc, const TPublicType& pType) error(loc, "boolean expression expected", "", ""); } -bool TParseContext::samplerErrorCheck(TSourceLoc loc, const TPublicType& pType, const char* reason) +void TParseContext::samplerCheck(TSourceLoc loc, const TType& type, const TString& identifier) { - if (pType.basicType == EbtStruct) { - if (containsSampler(*pType.userDef)) { - error(loc, reason, TType::getBasicString(pType.basicType), "(structure cannot contain a sampler or image)"); + if (type.getQualifier().storage == EvqUniform) + return; - return true; - } - - return false; - } else if (pType.basicType == EbtSampler) { - error(loc, reason, TType::getBasicString(pType.basicType), ""); - - return true; - } - - return false; + if (type.getBasicType() == EbtStruct && containsSampler(type)) + error(loc, "non-uniform struct contains a sampler or image:", type.getBasicTypeString().c_str(), identifier.c_str()); + else if (type.getBasicType() == EbtSampler && type.getQualifier().storage != EvqUniform) + error(loc, "sampler/image types can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str()); } // @@ -1544,11 +1536,6 @@ void TParseContext::globalQualifierCheck(TSourceLoc loc, const TQualifier& quali if (! symbolTable.atGlobalLevel()) return; - // Do non-in/out error checks - - if (qualifier.storage != EvqUniform && samplerErrorCheck(loc, publicType, "samplers and images must be uniform")) - return; - if (qualifier.storage != EvqVaryingIn && qualifier.storage != EvqVaryingOut) return; @@ -1738,7 +1725,7 @@ void TParseContext::precisionQualifierCheck(TSourceLoc loc, TPublicType& publicT void TParseContext::parameterSamplerCheck(TSourceLoc loc, TStorageQualifier qualifier, const TType& type) { if ((qualifier == EvqOut || qualifier == EvqInOut) && type.getBasicType() != EbtStruct && type.getBasicType() == EbtSampler) - error(loc, "samplers cannot be output parameters", type.getCompleteTypeString().c_str(), ""); + error(loc, "samplers cannot be output parameters", type.getBasicTypeString().c_str(), ""); } bool TParseContext::containsSampler(const TType& type) @@ -2147,28 +2134,41 @@ bool TParseContext::redeclareBuiltinBlock(TSourceLoc loc, TTypeList& typeList, c return true; } -void TParseContext::paramCheck(TSourceLoc loc, const TStorageQualifier& qualifier, TType* type) +void TParseContext::paramCheckFix(TSourceLoc loc, const TStorageQualifier& qualifier, TType& type) { switch (qualifier) { case EvqConst: case EvqConstReadOnly: - type->getQualifier().storage = EvqConstReadOnly; + type.getQualifier().storage = EvqConstReadOnly; break; case EvqIn: case EvqOut: case EvqInOut: - type->getQualifier().storage = qualifier; + type.getQualifier().storage = qualifier; break; case EvqTemporary: - type->getQualifier().storage = EvqIn; + type.getQualifier().storage = EvqIn; break; default: - type->getQualifier().storage = EvqIn; - error(loc, "qualifier not allowed on function parameter", GetStorageQualifierString(qualifier), ""); + type.getQualifier().storage = EvqIn; + error(loc, "storage qualifier not allowed on function parameter", GetStorageQualifierString(qualifier), ""); break; } } +void TParseContext::paramCheckFix(TSourceLoc loc, const TQualifier& qualifier, TType& type) +{ + if (qualifier.isAuxiliary() || + qualifier.isInterpolation()) + error(loc, "cannot use auxiliary or interpolation qualifiers on a function parameter", "", ""); + if (qualifier.hasLayout()) + error(loc, "cannot use layout qualifiers on a function parameter", "", ""); + if (qualifier.invariant) + error(loc, "cannot use invariant qualifier on a function parameter", "", ""); + + paramCheckFix(loc, qualifier.storage, type); +} + void TParseContext::nestedBlockCheck(TSourceLoc loc) { if (structNestingLevel > 0) @@ -2192,6 +2192,33 @@ void TParseContext::arrayObjectCheck(TSourceLoc loc, const TType& type, const ch } } +void TParseContext::opaqueCheck(TSourceLoc loc, const TType& type, const char* op) +{ + if (containsSampler(type)) + error(loc, "can't use with samplers or structs containing samplers", op, ""); +} + +void TParseContext::structTypeCheck(TSourceLoc loc, TPublicType& publicType) +{ + TTypeList& typeList = *publicType.userDef->getStruct(); + + // fix and check for member storage qualifiers and types that don't belong within a structure + for (unsigned int member = 0; member < typeList.size(); ++member) { + TQualifier& memberQualifier = typeList[member].type->getQualifier(); + TSourceLoc memberLoc = typeList[member].loc; + if (memberQualifier.isAuxiliary() || + memberQualifier.isInterpolation() || + (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal)) + error(memberLoc, "cannot use storage or interpolation qualifiers on structure members", typeList[member].type->getFieldName().c_str(), ""); + if (memberQualifier.isMemory()) + error(memberLoc, "cannot use memory qualifiers on structure members", typeList[member].type->getFieldName().c_str(), ""); + if (memberQualifier.hasLayout()) + error(memberLoc, "cannot use layout qualifiers on structure members", typeList[member].type->getFieldName().c_str(), ""); + if (memberQualifier.invariant) + error(memberLoc, "cannot use invariant qualifier on structure members", typeList[member].type->getFieldName().c_str(), ""); + } +} + // // See if this loop satisfies the limitations for ES 2.0 (version 100) for loops in Appendex A: // @@ -2738,6 +2765,9 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier, if (! initializer) nonInitConstCheck(loc, identifier, type); + invariantCheck(loc, type, identifier); + samplerCheck(loc, type, identifier); + // Pick up defaults if (! type.getQualifier().hasStream() && language == EShLangGeometry && type.getQualifier().storage == EvqVaryingOut) type.getQualifier().layoutStream = globalOutputDefaults.layoutStream; @@ -2775,6 +2805,9 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier, error(loc, "cannot change the type of", "redeclaration", symbol->getName().c_str()); } + if (! symbol) + return 0; + // Deal with initializer TIntermNode* initNode = 0; if (symbol && initializer) { @@ -2787,11 +2820,10 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier, } // look for errors/adjustments in layout qualifier use - if (symbol) - layoutTypeCheck(loc, *symbol); + layoutTypeCheck(loc, *symbol); // see if it's a linker-level object to track - if (symbol && newDeclaration && symbolTable.atGlobalLevel()) + if (newDeclaration && symbolTable.atGlobalLevel()) intermediate.addSymbolLinkageNode(linkage, *symbol); return initNode; @@ -3339,8 +3371,10 @@ void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, if (symbol->isReadOnly()) symbol = symbolTable.copyUp(symbol); - if (qualifier.invariant) + if (qualifier.invariant) { symbol->getWritableType().getQualifier().invariant = true; + invariantCheck(loc, symbol->getType(), identifier); + } } void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, TIdentifierList& identifiers) @@ -3349,6 +3383,22 @@ void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, addQualifierToExisting(loc, qualifier, *identifiers[i]); } +void TParseContext::invariantCheck(TSourceLoc loc, const TType& type, const TString& identifier) +{ + if (! type.getQualifier().invariant) + return; + + bool pipeOut = type.getQualifier().isPipeOutput(); + bool pipeIn = type.getQualifier().isPipeInput(); + if (version >= 300 || profile != EEsProfile && version >= 420) { + if (! pipeOut) + error(loc, "can only apply to an output\n", "invariant", identifier.c_str()); + } 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", ""); + } +} + // // Updating default qualifier for the case of a declaration with just a qualifier, // no type, block, or identifier. diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index 7ff225d7..6ae64569 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -111,7 +111,7 @@ public: bool voidErrorCheck(TSourceLoc, const TString&, TBasicType); void boolCheck(TSourceLoc, const TIntermTyped*); void boolCheck(TSourceLoc, const TPublicType&); - bool samplerErrorCheck(TSourceLoc, const TPublicType& pType, const char* reason); + void samplerCheck(TSourceLoc, const TType&, const TString& identifier); void pipeInOutFix(TSourceLoc, TQualifier&); void globalQualifierCheck(TSourceLoc, const TQualifier&, const TPublicType&); bool structQualifierErrorCheck(TSourceLoc, const TPublicType& pType); @@ -124,10 +124,13 @@ public: bool containsSampler(const TType& type); TSymbol* redeclareBuiltinVariable(TSourceLoc, const TString&, const TQualifier&, const TShaderQualifiers&, bool& newDeclaration); bool redeclareBuiltinBlock(TSourceLoc, TTypeList& typeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes); - void paramCheck(TSourceLoc, const TStorageQualifier&, TType* type); + void paramCheckFix(TSourceLoc, const TStorageQualifier&, TType& type); + void paramCheckFix(TSourceLoc, const TQualifier&, TType& type); void nestedBlockCheck(TSourceLoc); void nestedStructCheck(TSourceLoc); void arrayObjectCheck(TSourceLoc, const TType&, const char* op); + void opaqueCheck(TSourceLoc, const TType&, const char* op); + void structTypeCheck(TSourceLoc, TPublicType&); void inductiveLoopCheck(TSourceLoc, TIntermNode* init, TIntermLoop* loop); void inductiveLoopBodyCheck(TIntermNode*, int loopIndexId, TSymbolTable&); void constantIndexExpressionCheck(TIntermNode*); @@ -151,6 +154,7 @@ public: void declareBlock(TSourceLoc, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0); void addQualifierToExisting(TSourceLoc, TQualifier, const TString& identifier); void addQualifierToExisting(TSourceLoc, TQualifier, TIdentifierList&); + void invariantCheck(TSourceLoc, const TType&, const TString& identifier); void updateStandaloneQualifierDefaults(TSourceLoc, const TPublicType&); void updateTypedDefaults(TSourceLoc, const TQualifier&, const TString* id); void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode); diff --git a/glslang/MachineIndependent/SymbolTable.cpp b/glslang/MachineIndependent/SymbolTable.cpp index 2977a2e5..4c6cbcde 100644 --- a/glslang/MachineIndependent/SymbolTable.cpp +++ b/glslang/MachineIndependent/SymbolTable.cpp @@ -136,7 +136,7 @@ int TType::getStructSize() const void TVariable::dump(TInfoSink& infoSink) const { - infoSink.debug << getName().c_str() << ": " << type.getStorageQualifierString() << " " << type.getCompleteTypeString(); + infoSink.debug << getName().c_str() << ": " << type.getStorageQualifierString() << " " << type.getBasicTypeString(); if (type.isArray()) { infoSink.debug << "[0]"; } @@ -145,7 +145,7 @@ void TVariable::dump(TInfoSink& infoSink) const void TFunction::dump(TInfoSink& infoSink) const { - infoSink.debug << getName().c_str() << ": " << returnType.getCompleteTypeString() << " " << getMangledName().c_str() << "\n"; + infoSink.debug << getName().c_str() << ": " << returnType.getBasicTypeString() << " " << getMangledName().c_str() << "\n"; } void TAnonMember::dump(TInfoSink& TInfoSink) const diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index cd1966a2..bc7d0e27 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -552,6 +552,7 @@ equality_expression : relational_expression { $$ = $1; } | equality_expression EQ_OP relational_expression { parseContext.arrayObjectCheck($2.loc, $1->getType(), "array comparison"); + parseContext.opaqueCheck($2.loc, $1->getType(), "=="); $$ = parseContext.intermediate.addBinaryMath(EOpEqual, $1, $3, $2.loc); if ($$ == 0) { parseContext.binaryOpError($2.loc, "==", $1->getCompleteString(), $3->getCompleteString()); @@ -562,6 +563,7 @@ equality_expression } | equality_expression NE_OP relational_expression { parseContext.arrayObjectCheck($2.loc, $1->getType(), "array comparison"); + parseContext.opaqueCheck($2.loc, $1->getType(), "!="); $$ = parseContext.intermediate.addBinaryMath(EOpNotEqual, $1, $3, $2.loc); if ($$ == 0) { parseContext.binaryOpError($2.loc, "!=", $1->getCompleteString(), $3->getCompleteString()); @@ -664,6 +666,7 @@ assignment_expression : conditional_expression { $$ = $1; } | unary_expression assignment_operator assignment_expression { parseContext.arrayObjectCheck($2.loc, $1->getType(), "array assignment"); + parseContext.opaqueCheck($2.loc, $1->getType(), "="); parseContext.lValueErrorCheck($2.loc, "assign", $1); $$ = parseContext.intermediate.addAssign($2.op, $1, $3, $2.loc); if ($$ == 0) { @@ -921,13 +924,13 @@ parameter_declaration parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers); parseContext.parameterSamplerCheck($2.loc, $1.qualifier.storage, *$$.param.type); - parseContext.paramCheck($1.loc, $1.qualifier.storage, $$.param.type); + parseContext.paramCheckFix($1.loc, $1.qualifier, *$$.param.type); } | parameter_declarator { $$ = $1; parseContext.parameterSamplerCheck($1.loc, EvqIn, *$1.param.type); - parseContext.paramCheck($1.loc, EvqTemporary, $$.param.type); + parseContext.paramCheckFix($1.loc, EvqTemporary, *$$.param.type); } // // Without name @@ -939,13 +942,13 @@ parameter_declaration parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers); parseContext.parameterSamplerCheck($2.loc, $1.qualifier.storage, *$$.param.type); - parseContext.paramCheck($1.loc, $1.qualifier.storage, $$.param.type); + parseContext.paramCheckFix($1.loc, $1.qualifier, *$$.param.type); } | parameter_type_specifier { $$ = $1; parseContext.parameterSamplerCheck($1.loc, EvqIn, *$1.param.type); - parseContext.paramCheck($1.loc, EvqTemporary, $$.param.type); + parseContext.paramCheckFix($1.loc, EvqTemporary, *$$.param.type); } ; @@ -1015,6 +1018,7 @@ fully_specified_type : type_specifier { $$ = $1; + parseContext.globalQualifierCheck($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"); @@ -1950,6 +1954,7 @@ type_specifier_nonarray | struct_specifier { $$ = $1; $$.qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + parseContext.structTypeCheck($$.loc, $$); } | TYPE_NAME { //