diff --git a/Test/420.vert b/Test/420.vert index 3f4fa6990..04dd17092 100644 --- a/Test/420.vert +++ b/Test/420.vert @@ -12,6 +12,23 @@ 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 +int anonconst; +const int aconst = 5; +const int a = aconst; +const int b = anonconst; // ERROR at global scope + +const int foo() // ERROR, no const functions +{ + const int a = aconst; + const int b = anonconst; + const int c = a; // still compile-time const + const int d = b; // not a compile-time const + float x[c]; // okay + float y[d]; // ERROR + + return b; +} + void main() { int i; diff --git a/Test/baseResults/120.vert.out b/Test/baseResults/120.vert.out index bb956dea9..9f499f87b 100644 --- a/Test/baseResults/120.vert.out +++ b/Test/baseResults/120.vert.out @@ -24,14 +24,16 @@ ERROR: 0:39: 'arrays of arrays' : not supported with this profile: none ERROR: 0:40: 'arrays of arrays' : not supported with this profile: none ERROR: 0:40: 'constructor' : array constructor needs one argument per array element ERROR: 0:40: 'arrays of arrays' : not supported with this profile: none +ERROR: 0:40: '=' : cannot convert from 'const float' to '2-element array of float' ERROR: 0:41: 'arrays of arrays' : not supported with this profile: none ERROR: 0:41: 'constructor' : array constructor needs one argument per array element ERROR: 0:41: 'arrays of arrays' : not supported with this profile: none +ERROR: 0:41: '=' : cannot convert from 'const float' to '2-element array of float' ERROR: 0:50: 'arrays of arrays' : not supported with this profile: none ERROR: 0:51: 'arrays of arrays' : not supported with this profile: none ERROR: 0:52: 'arrays of arrays' : not supported with this profile: none ERROR: 0:53: 'arrays of arrays' : not supported with this profile: none -ERROR: 32 compilation errors. No code generated. +ERROR: 34 compilation errors. No code generated. ERROR: node is still EOpNull! 0:15 Function Definition: main( (void) @@ -75,14 +77,6 @@ ERROR: node is still EOpNull! 0:32 'a3' (int) 0:32 Constant: 0:32 12 (const int) -0:40 Sequence -0:40 move second child to first child (2-element array of float) -0:40 'md9' (2-element array of float) -0:40 Construct float (const 2-element array of float) -0:41 Sequence -0:41 move second child to first child (2-element array of float) -0:41 'md11' (2-element array of float) -0:41 Construct float (const 2-element array of float) 0:43 move second child to first child (float) 0:43 'gl_PointSize' (invariant gl_PointSize float) 0:43 Constant: diff --git a/Test/baseResults/420.tese.out b/Test/baseResults/420.tese.out index 415129bf2..2b5af43d2 100644 --- a/Test/baseResults/420.tese.out +++ b/Test/baseResults/420.tese.out @@ -8,10 +8,11 @@ ERROR: 0:27: '=' : cannot convert from 'const bool' to 'int' ERROR: 0:28: 'constructor' : cannot convert parameter 2 from 'const float' to '4-component vector of float' ERROR: 0:29: 'constructor' : cannot convert parameter 2 from 'const 2X2 matrix of float' to 'const 4-component vector of float' ERROR: 0:29: 'const 2-element array of 4-component vector of float' : cannot construct with these arguments +ERROR: 0:29: '=' : cannot convert from 'const float' to '2-element array of 4-component vector of float' ERROR: 0:30: 'initializer list' : wrong number of matrix columns: 4X2 matrix of float ERROR: 0:40: 'constructor' : cannot convert parameter 1 from 'float' to 'structure' ERROR: 0:58: 'initializer list' : wrong number of structure members -ERROR: 12 compilation errors. No code generated. +ERROR: 13 compilation errors. No code generated. ERROR: node is still EOpNull! 0:4 Sequence @@ -34,10 +35,6 @@ ERROR: node is still EOpNull! 0:20 Constant: 0:20 1.000000 0:20 3 (const int) -0:29 Sequence -0:29 move second child to first child (2-element array of 4-component vector of float) -0:29 'b4' (2-element array of 4-component vector of float) -0:29 Construct vec4 (const 2-element array of 4-component vector of float) 0:42 Sequence 0:42 move second child to first child (5-element array of float) 0:42 'b5' (5-element array of float) diff --git a/Test/baseResults/420.vert.out b/Test/baseResults/420.vert.out index 6703561aa..4201808d5 100644 --- a/Test/baseResults/420.vert.out +++ b/Test/baseResults/420.vert.out @@ -5,39 +5,56 @@ ERROR: 0:7: '' : vertex input cannot be further qualified ERROR: 0:11: '' : can only have one interpolation qualifier (flat, smooth, noperspective) ERROR: 0:12: '' : can only have one auxiliary qualifier (centroid, patch, and sample) ERROR: 0:13: 'uniform' : too many storage qualifiers -ERROR: 0:21: 'j' : undeclared identifier -ERROR: 0:21: '=' : cannot convert from 'float' to 'int' -ERROR: 0:22: 'k' : undeclared identifier -ERROR: 0:22: '=' : cannot convert from 'float' to 'int' -ERROR: 0:23: 'j' : undeclared identifier -ERROR: 0:23: '=' : cannot convert from 'float' to 'int' -ERROR: 0:27: 'jj' : undeclared identifier -ERROR: 0:27: '=' : cannot convert from 'float' to 'int' -ERROR: 13 compilation errors. No code generated. +ERROR: 0:18: '=' : global const initializers must be constant 'const int' +ERROR: 0:20: 'const' : no qualifiers allowed for function return +ERROR: 0:27: '' : constant expression required +ERROR: 0:27: '' : array size must be a constant integer expression +ERROR: 0:38: 'j' : undeclared identifier +ERROR: 0:38: '=' : cannot convert from 'float' to 'int' +ERROR: 0:39: 'k' : undeclared identifier +ERROR: 0:39: '=' : cannot convert from 'float' to 'int' +ERROR: 0:40: 'j' : undeclared identifier +ERROR: 0:40: '=' : cannot convert from 'float' to 'int' +ERROR: 0:44: 'jj' : undeclared identifier +ERROR: 0:44: '=' : cannot convert from 'float' to 'int' +ERROR: 17 compilation errors. No code generated. ERROR: node is still EOpNull! -0:15 Function Definition: main( (void) -0:15 Function Parameters: +0:20 Function Definition: foo( (const int) +0:20 Function Parameters: 0:? Sequence -0:18 Test condition and select (void) -0:18 Condition -0:18 Compare Equal (bool) -0:18 'i' (int) -0:18 Constant: -0:18 3 (const int) -0:18 true case -0:19 Sequence -0:19 move second child to first child (int) -0:19 'j' (int) -0:19 'i' (int) -0:25 Loop with condition tested first -0:25 Loop Condition -0:25 Constant: -0:25 true (const bool) -0:25 No loop body -0:30 Function Definition: bar(vf4; (void) -0:30 Function Parameters: -0:30 'v' (in 4-component vector of float) +0:23 Sequence +0:23 move second child to first child (int) +0:23 'b' (const (read only) int) +0:23 'anonconst' (int) +0:25 Sequence +0:25 move second child to first child (int) +0:25 'd' (const (read only) int) +0:25 'b' (const (read only) int) +0:29 Branch: Return with expression +0:29 'b' (const (read only) int) +0:32 Function Definition: main( (void) +0:32 Function Parameters: +0:? Sequence +0:35 Test condition and select (void) +0:35 Condition +0:35 Compare Equal (bool) +0:35 'i' (int) +0:35 Constant: +0:35 3 (const int) +0:35 true case +0:36 Sequence +0:36 move second child to first child (int) +0:36 'j' (int) +0:36 'i' (int) +0:42 Loop with condition tested first +0:42 Loop Condition +0:42 Constant: +0:42 true (const bool) +0:42 No loop body +0:47 Function Definition: bar(vf4; (void) +0:47 Function Parameters: +0:47 'v' (in 4-component vector of float) 0:? Linker Objects 0:? 'v2' (smooth out 2-component vector of float) 0:? 'bad' (in 10-element array of 4-component vector of float) @@ -48,6 +65,12 @@ ERROR: node is still EOpNull! 0:? 'rep' (smooth flat out 4-component vector of float) 0:? 'rep2' (centroid smooth sample out 4-component vector of float) 0:? 'rep3' (in 4-component vector of float) +0:? 'anonconst' (int) +0:? 'aconst' (const int) +0:? 5 (const int) +0:? 'a' (const int) +0:? 5 (const int) +0:? 'b' (int) 0:? 'gl_VertexID' (gl_VertexId int) 0:? 'gl_InstanceID' (gl_InstanceId int) diff --git a/Test/baseResults/array.frag.out b/Test/baseResults/array.frag.out index b87a9bf09..364018440 100644 --- a/Test/baseResults/array.frag.out +++ b/Test/baseResults/array.frag.out @@ -8,7 +8,7 @@ ERROR: 0:42: '[' : array index out of range '5' ERROR: 0:45: '[' : array index out of range '1000' ERROR: 0:46: '[' : array index out of range '-1' ERROR: 0:52: '[' : array index '2' out of range -ERROR: 0:54: 'const' : non-matching types for const initializer +ERROR: 0:54: 'const' : non-matching or non-convertible constant type for const initializer ERROR: 0:56: '=' : cannot convert from 'const 2-element array of int' to '3-element array of int' ERROR: 0:57: '[]' : scalar integer expression required ERROR: 0:57: '[' : array index out of range '-858993459' diff --git a/Test/baseResults/constErrors.frag.out b/Test/baseResults/constErrors.frag.out index bd249e2fc..48ec2499f 100644 --- a/Test/baseResults/constErrors.frag.out +++ b/Test/baseResults/constErrors.frag.out @@ -1,18 +1,23 @@ Warning, version 330 is not yet complete; some version-specific features are present, but many are missing. -ERROR: 0:14: '=' : assigning non-constant to 'const int' +ERROR: 0:14: 'non-constant initializer' : not supported for this version or the enabled extensions ERROR: 0:17: '' : constant expression required ERROR: 0:17: '' : array size must be a constant integer expression ERROR: 0:18: '' : constant expression required ERROR: 0:18: '' : array size must be a constant integer expression ERROR: 0:19: '' : constant expression required ERROR: 0:19: '' : array size must be a constant integer expression -ERROR: 0:27: '=' : assigning non-constant to 'const structure' -ERROR: 0:33: '=' : assigning non-constant to 'const structure' +ERROR: 0:27: '=' : global const initializers must be constant 'const structure' +ERROR: 0:33: '=' : global const initializers must be constant 'const structure' ERROR: 9 compilation errors. No code generated. ERROR: node is still EOpNull! 0:10 Function Definition: main( (void) 0:10 Function Parameters: +0:? Sequence +0:14 Sequence +0:14 move second child to first child (int) +0:14 'a3' (const (read only) int) +0:14 'uniformInt' (uniform int) 0:? Linker Objects 0:? 'inVar' (smooth in 4-component vector of float) 0:? 'outVar' (out 4-component vector of float) @@ -21,4 +26,6 @@ ERROR: node is still EOpNull! 0:? 'uniformInt' (uniform int) 0:? 's' (structure) 0:? 's2' (structure) +0:? 'f' (const float) +0:? 3.000000 diff --git a/Test/baseResults/matrixError.vert.out b/Test/baseResults/matrixError.vert.out index 65f623e44..fa5a82bd9 100644 --- a/Test/baseResults/matrixError.vert.out +++ b/Test/baseResults/matrixError.vert.out @@ -1,6 +1,6 @@ Warning, version 120 is not yet complete; most features are present, but a few are missing. ERROR: 0:10: 'constructor' : too many arguments -ERROR: 0:7: '=' : cannot assign to 'const 2X4 matrix of float' +ERROR: 0:7: 'const' : non-matching or non-convertible constant type for const initializer ERROR: 0:17: 'assign' : cannot convert from '2-component vector of float' to '3-component vector of float' ERROR: 0:18: 'assign' : cannot convert from '2-component vector of float' to '3-component vector of float' ERROR: 0:19: '.' : field selection not allowed on matrix diff --git a/Test/baseResults/specExamples.frag.out b/Test/baseResults/specExamples.frag.out index 9eb9566b0..a0e46f846 100644 --- a/Test/baseResults/specExamples.frag.out +++ b/Test/baseResults/specExamples.frag.out @@ -22,6 +22,7 @@ ERROR: 0:115: 'depth_greater' : unrecognized layout identifier ERROR: 0:118: 'depth_less' : unrecognized layout identifier ERROR: 0:121: 'depth_unchanged' : unrecognized layout identifier ERROR: 0:150: 'constructor' : constructing from a non-dereferenced array +ERROR: 0:150: '=' : cannot convert from 'const float' to '3-element array of 4-component vector of float' ERROR: 0:152: 'constructor' : cannot convert parameter 1 from 'const 2-element array of 4-component vector of float' to '4-component vector of float' ERROR: 0:172: 'x' : undeclared identifier ERROR: 0:172: '[]' : scalar integer expression required @@ -42,16 +43,12 @@ ERROR: 0:178: 'a' : dot operator requires structure, array, vector, or matrix o ERROR: 0:178: 'length' : dot operator requires structure, array, vector, or matrix on left hand side ERROR: 0:178: '' : function call, method, or subroutine call expected ERROR: 0:178: '' : no matching overloaded function found -ERROR: 0:193: '=' : cannot convert from 'const int' to 'structure' ERROR: 0:198: 'e' : redefinition -ERROR: 0:217: '=' : cannot convert from 'const float' to 'unsized array of float' -ERROR: 0:219: '=' : cannot convert from 'unsized array of float' to '5-element array of float' -ERROR: 0:223: '=' : assigning non-constant to 'const float' 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: 52 compilation errors. No code generated. +ERROR: 49 compilation errors. No code generated. ERROR: node is still EOpNull! 0:5 Sequence @@ -166,10 +163,6 @@ ERROR: node is still EOpNull! 0:149 0.100000 0:149 0.100000 0:149 0.100000 -0:150 Sequence -0:150 move second child to first child (3-element array of 4-component vector of float) -0:150 'a3' (3-element array of 4-component vector of float) -0:150 Construct vec4 (3-element array of 4-component vector of float) 0:? Sequence 0:159 Sequence 0:159 Sequence @@ -235,6 +228,14 @@ ERROR: node is still EOpNull! 0:219 move second child to first child (5-element array of float) 0:219 'd' (5-element array of float) 0:219 'b' (5-element array of float) +0:? Sequence +0:223 Sequence +0:223 move second child to first child (float) +0:223 'ceiling' (const (read only) float) +0:223 Convert int to float (float) +0:223 add (int) +0:223 'a' (int) +0:223 'b' (int) 0:? Linker Objects 0:? 'a' (int) 0:? 'b' (int) diff --git a/Test/baseResults/specExamples.vert.out b/Test/baseResults/specExamples.vert.out index 5edf37f6e..c06df108c 100644 --- a/Test/baseResults/specExamples.vert.out +++ b/Test/baseResults/specExamples.vert.out @@ -46,11 +46,10 @@ ERROR: 0:164: 'func' : no matching overloaded function found ERROR: 0:166: 'x' : dot operator requires structure, array, vector, or matrix on left hand side ERROR: 0:166: 'func2' : no matching overloaded function found ERROR: 0:167: 'x' : dot operator requires structure, array, vector, or matrix on left hand side -ERROR: 0:191: '=' : cannot convert from 'const 4-component vector of float' to '2-element array of 4-component vector of float' ERROR: 0:192: 'constructor' : constructing from a non-dereferenced array ERROR: 0:193: 'constructor' : constructing from a non-dereferenced array ERROR: 0:194: 'constructor' : constructing from a non-dereferenced array -ERROR: 51 compilation errors. No code generated. +ERROR: 50 compilation errors. No code generated. ERROR: node is still EOpNull! 0:134 Function Definition: funcA(I21; (4-component vector of float) @@ -244,9 +243,12 @@ ERROR: node is still EOpNull! 0:191 1.000000 0:191 1.000000 0:191 1.000000 -0:192 Construct vec4 (3-element array of 4-component vector of float) -0:193 Construct vec4 (3-element array of 4-component vector of float) -0:194 Construct vec4 (3-element array of 4-component vector of float) +0:192 Constant: +0:192 0.000000 +0:193 Constant: +0:193 0.000000 +0:194 Constant: +0:194 0.000000 0:? Linker Objects 0:? 'Coords' (out block) 0:? '__anon__0' (out block) diff --git a/Test/baseResults/uint.frag.out b/Test/baseResults/uint.frag.out index 2a14b8ad1..428df239b 100644 --- a/Test/baseResults/uint.frag.out +++ b/Test/baseResults/uint.frag.out @@ -1,9 +1,9 @@ ERROR: 0:2: 'uint' : must be qualified as flat in ERROR: 0:6: 'in' : cannot be bool -ERROR: 0:20: 'const' : non-matching types for const initializer -ERROR: 0:24: 'const' : non-matching types for const initializer -ERROR: 0:34: 'const' : non-matching types for const initializer -ERROR: 0:37: 'const' : non-matching types for const initializer +ERROR: 0:20: 'const' : non-matching or non-convertible constant type for const initializer +ERROR: 0:24: 'const' : non-matching or non-convertible constant type for const initializer +ERROR: 0:34: 'const' : non-matching or non-convertible constant type for const initializer +ERROR: 0:37: 'const' : non-matching or non-convertible constant type for const initializer ERROR: 0:48: '=' : cannot convert from 'const int' to 'mediump uint' ERROR: 0:51: '=' : cannot convert from 'const int' to 'mediump uint' ERROR: 0:63: 'float' : type requires declaration of default precision qualifier diff --git a/Test/constErrors.frag b/Test/constErrors.frag index df49afcd4..0067af118 100644 --- a/Test/constErrors.frag +++ b/Test/constErrors.frag @@ -31,3 +31,5 @@ const struct S2 { ivec2 iv2; mat2x4 m; } s2 = S2(vec3(3.0), ivec2(3, constInt), mat2x4(1.0, 2.0, 3.0, inVar.x, 5.0, 6.0, 7.0, 8.0)); // ERROR, non-constant matrix + +const float f = 3; // okay, type conversion diff --git a/glslang/Include/BaseTypes.h b/glslang/Include/BaseTypes.h index 095ee2363..93fa11a0f 100644 --- a/glslang/Include/BaseTypes.h +++ b/glslang/Include/BaseTypes.h @@ -64,7 +64,7 @@ enum TBasicType { enum TStorageQualifier { EvqTemporary, // For temporaries (within a function), read/write EvqGlobal, // For globals read/write - EvqConst, // User defined constants and non-output parameters in functions + EvqConst, // User-defined constant values, will be semantically constant and constant folded EvqVaryingIn, // pipeline input, read only EvqVaryingOut, // pipeline ouput, read/write EvqUniform, // read only, shader with app @@ -74,7 +74,8 @@ enum TStorageQualifier { EvqIn, // also, for 'in' in the grammar before we know if it's a pipeline input or an 'in' parameter EvqOut, // also, for 'out' in the grammar before we know if it's a pipeline output or an 'out' parameter EvqInOut, - EvqConstReadOnly, + + EvqConstReadOnly, // read-only types, not having a constant value or constant-value semantics // built-ins read by vertex shader EvqVertexId, diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 442023aba..11543804e 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -799,9 +799,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal // Their parameters will be verified algorithmically. // TType type(EbtVoid); // use this to get the type back - if (constructorError(loc, intermNode, *fnCall, op, type)) { - result = 0; - } else { + if (! constructorError(loc, intermNode, *fnCall, op, type)) { // // It's a constructor, of type 'type'. // @@ -809,9 +807,6 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal if (result == 0) error(loc, "cannot construct with these arguments", type.getCompleteString().c_str(), ""); } - - if (result == 0) - result = intermediate.setAggregateOperator(0, op, type, loc); } else { // // Not a constructor. Find it in the symbol table. @@ -832,7 +827,6 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal error(intermNode->getLoc(), " wrong operand type", "Internal Error", "built in unary operator function. Type: %s", static_cast(intermNode)->getCompleteString().c_str()); - return 0; } } else { // This is a function call not mapped to built-in operation @@ -872,6 +866,14 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal } } + // generic error recovery + // TODO: coding: localize all the error recoveries that look like this + if (result == 0) { + TConstUnionArray unionArray(1); + unionArray[0].setDConst(0.0); + result = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), loc); + } + return result; } @@ -1197,7 +1199,7 @@ bool TParseContext::lValueErrorCheck(TSourceLoc loc, const char* op, TIntermType // Both test, and if necessary spit out an error, to see if the node is really // a constant. // -void TParseContext::constCheck(TIntermTyped* node, const char* token) +void TParseContext::constantValueCheck(TIntermTyped* node, const char* token) { if (node->getQualifier().storage != EvqConst) error(node->getLoc(), "constant expression required", token, ""); @@ -1827,9 +1829,10 @@ void TParseContext::updateMaxArraySize(TSourceLoc loc, TIntermNode *node, int in void TParseContext::nonInitConstCheck(TSourceLoc loc, TString& identifier, TType& type) { // - // Make the qualifier make sense. + // Make the qualifier make sense, given that there is an initializer. // - if (type.getQualifier().storage == EvqConst) { + if (type.getQualifier().storage == EvqConst || + type.getQualifier().storage == EvqConstReadOnly) { type.getQualifier().storage = EvqTemporary; error(loc, "variables with qualifier 'const' must be initialized", identifier.c_str(), ""); } @@ -2242,6 +2245,9 @@ TVariable* TParseContext::declareNonArray(TSourceLoc loc, TString& identifier, T // // Handle all types of initializers from the grammar. // +// Returning 0 just means there is no code to execute to handle the +// initializer, which will, for example, be the case for constant initalizers. +// TIntermNode* TParseContext::executeInitializer(TSourceLoc loc, TString& identifier, TIntermTyped* initializer, TVariable* variable) { @@ -2274,37 +2280,43 @@ TIntermNode* TParseContext::executeInitializer(TSourceLoc loc, TString& identifi variable->getType().isArray() && variable->getType().getArraySize() == 0) variable->getWritableType().changeArraySize(initializer->getType().getArraySize()); - // - // test for and propagate constant - // - if (qualifier == EvqConst || qualifier == EvqUniform) { + // Uniform and global consts require a constant initializer + if (qualifier == EvqUniform && initializer->getType().getQualifier().storage != EvqConst) { + error(loc, "uniform initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str()); + variable->getWritableType().getQualifier().storage = EvqTemporary; + return 0; + } + if (qualifier == EvqConst && symbolTable.atGlobalLevel() && initializer->getType().getQualifier().storage != EvqConst) { + error(loc, "global const initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str()); + variable->getWritableType().getQualifier().storage = EvqTemporary; + return 0; + } + + // Const variables require a constant initializer, depending on version + if (qualifier == EvqConst) { if (initializer->getType().getQualifier().storage != EvqConst) { - error(loc, " assigning non-constant to", "=", "'%s'", variable->getType().getCompleteString().c_str()); - variable->getWritableType().getQualifier().storage = EvqTemporary; - return 0; - } - if (variable->getType() != initializer->getType()) { - error(loc, " non-matching types for const initializer ", - variable->getType().getStorageQualifierString(), ""); - variable->getWritableType().getQualifier().storage = EvqTemporary; - return 0; - } - if (initializer->getAsConstantUnion()) - variable->setConstArray(initializer->getAsConstantUnion()->getConstArray()); - else if (initializer->getAsSymbolNode()) { - TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getName()); - if (const TVariable* tVar = symbol->getAsVariable()) - variable->setConstArray(tVar->getConstArray()); - else { - error(loc, "expected variable", initializer->getAsSymbolNode()->getName().c_str(), ""); - return 0; - } - } else { - error(loc, " cannot assign to", "=", "'%s'", variable->getType().getCompleteString().c_str()); + const char* initFeature = "non-constant initializer"; + requireProfile(loc, ECoreProfile | ECompatibilityProfile, initFeature); + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, GL_ARB_shading_language_420pack, initFeature); + variable->getWritableType().getQualifier().storage = EvqConstReadOnly; + qualifier = EvqConstReadOnly; + } + } + + if (qualifier == EvqConst || qualifier == EvqUniform) { + // Compile-time tagging of the variable with it's constant value... + + initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer); + if (! initializer || ! initializer->getAsConstantUnion() || variable->getType() != initializer->getType()) { + error(loc, "non-matching or non-convertible constant type for const initializer", + variable->getType().getStorageQualifierString(), ""); variable->getWritableType().getQualifier().storage = EvqTemporary; return 0; } + + variable->setConstArray(initializer->getAsConstantUnion()->getConstArray()); } else { + // normal assigning of a value to a variable... TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), loc); TIntermNode* initNode = intermediate.addAssign(EOpAssign, intermSymbol, initializer, loc); if (! initNode) diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index 208e5faab..a7de01ac2 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -90,7 +90,7 @@ public: void binaryOpError(TSourceLoc, const char* op, TString left, TString right); void variableCheck(TIntermTyped*& nodePtr); bool lValueErrorCheck(TSourceLoc, const char* op, TIntermTyped*); - void constCheck(TIntermTyped* node, const char* token); + void constantValueCheck(TIntermTyped* node, const char* token); void integerCheck(TIntermTyped* node, const char* token); void globalCheck(TSourceLoc, const char* token); bool constructorError(TSourceLoc, TIntermNode*, TFunction&, TOperator, TType&); diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index c71592571..4c4f08c2e 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -300,8 +300,6 @@ integer_expression function_call : function_call_or_method { $$ = parseContext.handleFunctionCall($1.loc, $1.function, $1.intermNode, $1.intermAggregate); - if ($$ == 0) - YYERROR; delete $1.function; } ; @@ -738,7 +736,7 @@ expression constant_expression : conditional_expression { - parseContext.constCheck($1, ""); + parseContext.constantValueCheck($1, ""); $$ = $1; } ; @@ -1160,7 +1158,7 @@ single_type_qualifier storage_qualifier : CONST { $$.init($1.loc); - $$.qualifier.storage = EvqConst; + $$.qualifier.storage = EvqConst; // will later turn into EvqConstReadOnly, if the initializer is not constant } | ATTRIBUTE { parseContext.requireStage($1.loc, EShLangVertex, "attribute"); @@ -2247,7 +2245,7 @@ switch_statement_list case_label : CASE expression COLON { - parseContext.constCheck($2, "case"); + parseContext.constantValueCheck($2, "case"); parseContext.integerCheck($2, "case"); $$ = parseContext.intermediate.addBranch(EOpCase, $2, $1.loc); }