diff --git a/Test/130.frag b/Test/130.frag index 1f547123..f46a818f 100644 --- a/Test/130.frag +++ b/Test/130.frag @@ -9,9 +9,9 @@ precision highp float; in vec4 i; out vec4 o; -in flat float fflat; -in smooth float fsmooth; -in noperspective float fnop; +flat in float fflat; +smooth in float fsmooth; +noperspective in float fnop; void main() { diff --git a/Test/300.vert b/Test/300.vert index aa881e96..7f5f3268 100644 --- a/Test/300.vert +++ b/Test/300.vert @@ -5,9 +5,17 @@ uniform mat3x3 m33; uniform mat4x4 m44; in vec3 v3; -varying vec2 v2; // ERROR - -in vec4 bad[10]; // ERROR +varying vec2 v2; // ERROR, varying reserved +in vec4 bad[10]; // ERROR, no arrayed inputs +highp in vec4 badorder; // ERROR, incorrect qualifier order +out invariant vec4 badorder2; // ERROR, incorrect qualifier order +in centroid vec4 badorder4; // ERROR, incorrect qualifier order +out flat vec4 badorder3; // ERROR, incorrect qualifier order +void bar(in const float a); // ERROR, incorrect qualifier order +void bar2(highp in float b); // ERROR, incorrect qualifier order +smooth flat out vec4 rep; // ERROR, replicating interpolation qualification +centroid sample out vec4 rep2; // ERROR, replicating auxiliary qualification +in uniform vec4 rep3; // ERROR, replicating storage qualification struct S { vec3 c; diff --git a/Test/420.vert b/Test/420.vert new file mode 100644 index 00000000..bb051f18 --- /dev/null +++ b/Test/420.vert @@ -0,0 +1,13 @@ +#version 420 core + +varying vec2 v2; // ERROR, varying reserved +in vec4 bad[10]; +highp in vec4 badorder; +out invariant vec4 badorder2; +in centroid vec4 badorder4; // ERROR, no centroid input to vertex stage +out flat vec4 badorder3; +void bar(in const float a); +void bar2(highp in float b); +smooth flat out vec4 rep; // ERROR, replicating interpolation qualification +centroid sample out vec4 rep2; // ERROR, replicating auxiliary qualification +in uniform vec4 rep3; // ERROR, replicating storage qualification diff --git a/Test/switch.frag b/Test/switch.frag index ddd38f64..d83eac63 100644 --- a/Test/switch.frag +++ b/Test/switch.frag @@ -1,7 +1,7 @@ #version 300 es uniform int c, d; -highp in float x; +in highp float x; void main() { diff --git a/Test/testlist b/Test/testlist index c549a3e7..e6707898 100644 --- a/Test/testlist +++ b/Test/testlist @@ -39,4 +39,5 @@ uint.frag switch.frag tokenLength.vert 300scope.vert +420.vert 430scope.vert diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index 8081ca26..1a7215d5 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -250,7 +250,7 @@ public: { return flat || smooth || nopersp; } - bool isAuxillary() const + bool isAuxiliary() const { return centroid || patch || sample; } diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index bf11314d..b549953c 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -757,7 +757,7 @@ void TParseContext::globalQualifierFix(int line, TQualifier& qualifier, const TP } if (language == EShLangVertex && qualifier.storage == EvqVaryingIn && - (qualifier.isAuxillary() || qualifier.isInterpolation() || qualifier.isMemory() || qualifier.invariant)) { + (qualifier.isAuxiliary() || qualifier.isInterpolation() || qualifier.isMemory() || qualifier.invariant)) { error(line, "vertex input cannot be further qualified", "", ""); return; @@ -768,38 +768,62 @@ void TParseContext::globalQualifierFix(int line, TQualifier& qualifier, const TP // Merge characteristics of the 'src' qualifier into the 'dst'. // If there is duplication, issue error messages, unless 'force' // is specified, which means to just override default settings. +// +// Also, when force is false, it will be assumed that 'src' follows +// 'dst', for the purpose of error checking order for versions +// that require specific orderings of qualifiers. // -void TParseContext::mergeQualifiers(int line, TPublicType& dst, const TPublicType& src, bool force) +void TParseContext::mergeQualifiers(int line, TQualifier& dst, const TQualifier& src, bool force) { - bool bad = false; + // Multiple auxiliary qualifiers (mostly done later by 'individual qualifiers') + if (src.isAuxiliary() && dst.isAuxiliary()) + error(line, "can only have one auxiliary qualifier (centroid, patch, and sample)", "", ""); + + // Multiple interpolation qualifiers (mostly done later by 'individual qualifiers') + if (src.isInterpolation() && dst.isInterpolation()) + error(line, "can only have one interpolation qualifier (flat, smooth, noperspective)", "", ""); + + // Ordering + if (! force && version < 420) { + // non-function parameters + if (src.invariant && (dst.isInterpolation() || dst.isAuxiliary() || dst.storage != EvqTemporary || dst.precision != EpqNone)) + error(line, "invariant qualifier must appear first", "", ""); + else if (src.isInterpolation() && (dst.isAuxiliary() || dst.storage != EvqTemporary || dst.precision != EpqNone)) + error(line, "interpolation qualifiers must appear before storage and precision qualifiers", "", ""); + else if (src.isAuxiliary() && (dst.storage != EvqTemporary || dst.precision != EpqNone)) + error(line, "Auxiliary qualifiers (centroid, patch, and sample) must appear before storage and precision qualifiers", "", ""); + else if (src.storage != EvqTemporary && (dst.precision != EpqNone)) + error(line, "precision qualifier must appear as last qualifier", "", ""); + + // function parameters + if (src.storage == EvqConst && (dst.storage == EvqIn || dst.storage == EvqOut)) + error(line, "in/out must appear before const", "", ""); + } // Storage qualification - if (dst.qualifier.storage == EvqTemporary || dst.qualifier.storage == EvqGlobal) - dst.qualifier.storage = src.qualifier.storage; - else if (dst.qualifier.storage == EvqIn && src.qualifier.storage == EvqOut || - dst.qualifier.storage == EvqOut && src.qualifier.storage == EvqIn) - dst.qualifier.storage = EvqInOut; - else if (dst.qualifier.storage == EvqIn && src.qualifier.storage == EvqConst || - dst.qualifier.storage == EvqConst && src.qualifier.storage == EvqIn) - dst.qualifier.storage = EvqConstReadOnly; - else if (src.qualifier.storage != EvqTemporary) { - error(line, "too many storage qualifiers", getStorageQualifierString(src.qualifier.storage), ""); - bad = true; - } + if (dst.storage == EvqTemporary || dst.storage == EvqGlobal) + dst.storage = src.storage; + else if (dst.storage == EvqIn && src.storage == EvqOut || + dst.storage == EvqOut && src.storage == EvqIn) + dst.storage = EvqInOut; + else if (dst.storage == EvqIn && src.storage == EvqConst || + dst.storage == EvqConst && src.storage == EvqIn) + dst.storage = EvqConstReadOnly; + else if (src.storage != EvqTemporary) + error(line, "too many storage qualifiers", getStorageQualifierString(src.storage), ""); // Precision qualifiers - if (! force && src.qualifier.precision != EpqNone && dst.qualifier.precision != EpqNone) { - error(line, "only one precision qualifier allowed", getPrecisionQualifierString(src.qualifier.precision), ""); - bad = true; - } - if (dst.qualifier.precision == EpqNone || force && src.qualifier.precision != EpqNone) - dst.qualifier.precision = src.qualifier.precision; + if (! force && src.precision != EpqNone && dst.precision != EpqNone) + error(line, "only one precision qualifier allowed", getPrecisionQualifierString(src.precision), ""); + if (dst.precision == EpqNone || force && src.precision != EpqNone) + dst.precision = src.precision; // Layout qualifiers - mergeLayoutQualifiers(line, dst.qualifier, src.qualifier); + mergeLayoutQualifiers(line, dst, src); - // other qualifiers - #define MERGE_SINGLETON(field) bad |= dst.qualifier.field && src.qualifier.field; dst.qualifier.field |= src.qualifier.field; + // individual qualifiers + bool repeated = false; + #define MERGE_SINGLETON(field) repeated |= dst.field && src.field; dst.field |= src.field; MERGE_SINGLETON(invariant); MERGE_SINGLETON(centroid); MERGE_SINGLETON(smooth); @@ -814,7 +838,7 @@ void TParseContext::mergeQualifiers(int line, TPublicType& dst, const TPublicTyp MERGE_SINGLETON(readonly); MERGE_SINGLETON(writeonly); - if (bad) + if (repeated) error(line, "replicated qualifiers", "", ""); } @@ -1562,8 +1586,8 @@ void TParseContext::addBlock(int line, TTypeList& typeList, const TString* insta TQualifier memberQualifier = typeList[member].type->getQualifier(); if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != currentBlockDefaults.storage) error(line, "member storage qualifier cannot contradict block storage qualifier", typeList[member].type->getFieldName().c_str(), ""); - if (currentBlockDefaults.storage == EvqUniform && memberQualifier.isInterpolation() || memberQualifier.isAuxillary()) - error(line, "member of uniform block cannot have an auxillary or interpolation qualifier", typeList[member].type->getFieldName().c_str(), ""); + if (currentBlockDefaults.storage == EvqUniform && memberQualifier.isInterpolation() || memberQualifier.isAuxiliary()) + error(line, "member of uniform block cannot have an auxiliary or interpolation qualifier", typeList[member].type->getFieldName().c_str(), ""); TBasicType basicType = typeList[member].type->getBasicType(); if (basicType == EbtSampler) @@ -1631,12 +1655,12 @@ void TParseContext::addQualifierToExisting(int line, TQualifier qualifier, const return; } - if (qualifier.isAuxillary() || + if (qualifier.isAuxiliary() || qualifier.isMemory() || qualifier.isInterpolation() || qualifier.storage != EvqTemporary || qualifier.precision != EpqNone) { - error(line, "cannot add storage, auxillary, memory, interpolation, or precision qualifier to an existing variable", identifier.c_str(), ""); + error(line, "cannot add storage, auxiliary, memory, interpolation, or precision qualifier to an existing variable", identifier.c_str(), ""); return; } @@ -1676,11 +1700,11 @@ void TParseContext::updateQualifierDefaults(TQualifier qualifier) void TParseContext::updateQualifierDefaults(int line, TQualifier qualifier) { - if (qualifier.isAuxillary() || + if (qualifier.isAuxiliary() || qualifier.isMemory() || qualifier.isInterpolation() || qualifier.precision != EpqNone) - error(line, "cannot use auxillary, memory, interpolation, or precision qualifier in a standalone qualifier", "", ""); + error(line, "cannot use auxiliary, memory, interpolation, or precision qualifier in a standalone qualifier", "", ""); switch (qualifier.storage) { case EvqUniform: diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index 4d29186e..efaa6c6a 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -128,7 +128,7 @@ struct TParseContext { bool samplerErrorCheck(int line, const TPublicType& pType, const char* reason); void globalQualifierFix(int line, TQualifier&, const TPublicType&); bool structQualifierErrorCheck(int line, const TPublicType& pType); - void mergeQualifiers(int line, TPublicType& dst, const TPublicType& src, bool force); + void mergeQualifiers(int line, TQualifier& dst, const TQualifier& src, bool force); void setDefaultPrecision(int line, TPublicType&, TPrecisionQualifier); int computeSamplerTypeIndex(TSampler&); TPrecisionQualifier getDefaultPrecision(TPublicType&); diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index a5fa9072..3cd084e2 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -1487,7 +1487,7 @@ fully_specified_type if ($2.arraySizes && parseContext.arrayQualifierError($2.line, $1)) $2.arraySizes = 0; - parseContext.mergeQualifiers($2.line, $2, $1, true); + parseContext.mergeQualifiers($2.line, $2.qualifier, $1.qualifier, true); parseContext.precisionQualifierCheck($2.line, $2); $$ = $2; @@ -1575,7 +1575,7 @@ type_qualifier if ($$.basicType == EbtVoid) $$.basicType = $2.basicType; - parseContext.mergeQualifiers($$.line, $$, $2, false); + parseContext.mergeQualifiers($$.line, $$.qualifier, $2.qualifier, false); } ; @@ -2487,7 +2487,7 @@ struct_declaration $$ = $3; parseContext.voidErrorCheck($2.line, (*$3)[0].type->getFieldName(), $2); - parseContext.mergeQualifiers($2.line, $2, $1, true); + parseContext.mergeQualifiers($2.line, $2.qualifier, $1.qualifier, true); parseContext.precisionQualifierCheck($2.line, $2); for (unsigned int i = 0; i < $$->size(); ++i)