From c719481d4329ce060a076f08628011d7ed766e14 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Mon, 9 Dec 2013 00:37:46 +0000 Subject: [PATCH] Flesh out 4.x block redeclaration semantics: - hide non-redeclared anonymous members - array size limit checking - illegal member qualifiers - additional members git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@24406 e7fa87d3-cd2b-0410-9028-fcbf551c1848 --- Test/330.frag | 16 ++ Test/400.geom | 1 + Test/410.geom | 6 +- Test/420.geom | 5 + Test/420.vert | 4 + Test/baseResults/330.frag.out | 16 +- Test/baseResults/400.geom.out | 62 +++---- Test/baseResults/410.geom.out | 20 ++- Test/baseResults/420.geom.out | 5 +- Test/baseResults/420.vert.out | 1 + Test/baseResults/430.vert.out | 6 +- Test/baseResults/decls.frag.out | 16 +- glslang/Include/Types.h | 8 +- glslang/Include/revision.h | 4 +- glslang/MachineIndependent/ParseHelper.cpp | 181 +++++++++++++-------- glslang/MachineIndependent/ParseHelper.h | 5 +- 16 files changed, 229 insertions(+), 127 deletions(-) diff --git a/Test/330.frag b/Test/330.frag index 26b98daa..22143f84 100644 --- a/Test/330.frag +++ b/Test/330.frag @@ -23,3 +23,19 @@ void foo() vec4 c = gl_Color; outVar = inVar; } + +in gl_block { // ERROR + int gl_i; +} gl_name; + +in myBlock { + int gl_i; // ERROR +} gl_name; // ERROR + +in gl_PerVertex { // ERROR + vec4 gl_FragCoord; +} gl_in[]; + +in gl_PerVertex { // ERROR + vec4 gl_FragCoord; +}; // ERROR diff --git a/Test/400.geom b/Test/400.geom index 9699ef7f..1354d479 100644 --- a/Test/400.geom +++ b/Test/400.geom @@ -17,6 +17,7 @@ layout(max_vertices = 127, invocations = 4) out; in gl_PerVertex { // testing input arrays with a block redeclaration, see 420.geom for without vec4 gl_Position; + layout(std140, location = 3) patch float gl_PointSize; // ERRORs... } gl_in[]; void foo() diff --git a/Test/410.geom b/Test/410.geom index af3dbac1..116d6fec 100644 --- a/Test/410.geom +++ b/Test/410.geom @@ -27,6 +27,8 @@ out gl_PerVertex { void foo() { - float p = gl_in[1].gl_PointSize; // use of redeclared - gl_PointSize = p; // use of redeclared + float p = gl_in[1].gl_PointSize; // use of redeclared + gl_PointSize = p; // use of redeclared + vec4 v = gl_in[1].gl_Position; // ERROR, not included in the redeclaration + gl_Position = vec4(1.0); // ERROR, not included in the redeclaration } diff --git a/Test/420.geom b/Test/420.geom index 49c6fccf..2d632567 100644 --- a/Test/420.geom +++ b/Test/420.geom @@ -43,3 +43,8 @@ void foo4() v4.x = 3.2; // ERROR v4.xy; // should have non-uniform type } + +out gl_PerVertex { + float gl_PointSize[1]; // ERROR, adding array + float gl_ClipDistance; // ERROR, removing array +}; diff --git a/Test/420.vert b/Test/420.vert index b9ead7f1..5e40e26c 100644 --- a/Test/420.vert +++ b/Test/420.vert @@ -77,3 +77,7 @@ layout(binding = 31) uniform sampler2D sampb5[2]; // ERROR, binding too big int fgfg(float f, mediump int i); int fgfg(float f, highp int i); + +out gl_PerVertex { + float gl_ClipDistance[4]; +}; diff --git a/Test/baseResults/330.frag.out b/Test/baseResults/330.frag.out index 0e7ce4dd..66dd5a37 100644 --- a/Test/baseResults/330.frag.out +++ b/Test/baseResults/330.frag.out @@ -1,7 +1,14 @@ 330.frag Warning, version 330 is not yet complete; some version-specific features are present, but many are missing. +ERROR: 0:27: 'block declaration' : cannot redeclare block: gl_block +ERROR: 0:31: 'gl_' : reserved built-in name: gl_name +ERROR: 0:32: 'gl_' : reserved built-in name: gl_i +ERROR: 0:35: 'gl_in' : no declaration found for redeclaration +ERROR: 0:39: 'gl_FragCoord' : cannot redeclare a non block as a block +ERROR: 5 compilation errors. No code generated. -0:? Sequence + +ERROR: node is still EOpNull! 0:8 Function Definition: main( (void) 0:8 Function Parameters: 0:10 Sequence @@ -26,9 +33,9 @@ Warning, version 330 is not yet complete; some version-specific features are pre 0:23 move second child to first child (4-component vector of float) 0:23 'c' (4-component vector of float) 0:23 gl_Color: direct index for structure (in 4-component vector of float) -0:23 '__anon__0' (in block{gl_Color}) +0:23 '__anon__0' (in block{gl_Color,}) 0:23 Constant: -0:23 0 (const uint) +0:23 2 (const uint) 0:24 move second child to first child (4-component vector of float) 0:24 'outVar' (out 4-component vector of float) 0:24 'inVar' (smooth in 4-component vector of float) @@ -36,7 +43,8 @@ Warning, version 330 is not yet complete; some version-specific features are pre 0:? 'inVar' (smooth in 4-component vector of float) 0:? 'outVar' (out 4-component vector of float) 0:? 'varyingVar' (smooth in 4-component vector of float) -0:? '__anon__0' (in block{gl_Color}) +0:? '__anon__0' (in block{gl_Color,}) +0:? 'gl_name' (in block{gl_i}) Linked fragment stage: diff --git a/Test/baseResults/400.geom.out b/Test/baseResults/400.geom.out index 937fda1b..8fd9f213 100644 --- a/Test/baseResults/400.geom.out +++ b/Test/baseResults/400.geom.out @@ -1,12 +1,14 @@ 400.geom Warning, version 400 is not yet complete; some version-specific features are present, but many are missing. ERROR: 0:13: 'invocations' : can only apply to a standalone qualifier -ERROR: 0:24: 'length' : array must be declared with a size before using this method -ERROR: 0:35: 'length' : array must be declared with a size before using this method -ERROR: 0:39: 'triangles' : inconsistent input primitive for array size colorBad -ERROR: 0:43: 'triangles' : inconsistent input primitive for array size colorbad2 -ERROR: 0:55: 'location' : repeated use of location 4 -ERROR: 6 compilation errors. No code generated. +ERROR: 0:20: 'gl_PointSize' : cannot add layout to redeclared block member +ERROR: 0:20: 'gl_PointSize' : cannot add patch to redeclared block member +ERROR: 0:25: 'length' : array must be declared with a size before using this method +ERROR: 0:36: 'length' : array must be declared with a size before using this method +ERROR: 0:40: 'triangles' : inconsistent input primitive for array size colorBad +ERROR: 0:44: 'triangles' : inconsistent input primitive for array size colorbad2 +ERROR: 0:56: 'location' : repeated use of location 4 +ERROR: 8 compilation errors. No code generated. invocations = 4 @@ -29,39 +31,39 @@ ERROR: node is still EOpNull! 0:10 move second child to first child (int) 0:10 'id' (int) 0:10 'gl_InvocationID' (in int) -0:22 Function Definition: foo( (void) -0:22 Function Parameters: -0:24 Sequence -0:24 Constant: -0:24 1 (const int) -0:25 gl_Position: direct index for structure (4-component vector of float) -0:25 direct index (block{gl_Position}) -0:25 'gl_in' (in 3-element array of block{gl_Position}) -0:25 Constant: -0:25 1 (const int) -0:25 Constant: -0:25 0 (const int) -0:33 Function Definition: foo2( (void) -0:33 Function Parameters: -0:35 Sequence -0:35 Constant: -0:35 1 (const int) +0:23 Function Definition: foo( (void) +0:23 Function Parameters: +0:25 Sequence +0:25 Constant: +0:25 1 (const int) +0:26 gl_Position: direct index for structure (4-component vector of float) +0:26 direct index (block{gl_Position,gl_PointSize}) +0:26 'gl_in' (in 3-element array of block{gl_Position,gl_PointSize}) +0:26 Constant: +0:26 1 (const int) +0:26 Constant: +0:26 0 (const int) +0:34 Function Definition: foo2( (void) +0:34 Function Parameters: +0:36 Sequence 0:36 Constant: -0:36 3 (const int) -0:45 Function Definition: foo3( (void) -0:45 Function Parameters: -0:47 Sequence -0:47 Constant: -0:47 3 (const int) +0:36 1 (const int) +0:37 Constant: +0:37 3 (const int) +0:46 Function Definition: foo3( (void) +0:46 Function Parameters: +0:48 Sequence 0:48 Constant: 0:48 3 (const int) 0:49 Constant: 0:49 3 (const int) 0:50 Constant: 0:50 3 (const int) +0:51 Constant: +0:51 3 (const int) 0:? Linker Objects 0:? '__anon__0' (layout(stream=0 ) out block{a}) -0:? 'gl_in' (in 3-element array of block{gl_Position}) +0:? 'gl_in' (in 3-element array of block{gl_Position,gl_PointSize}) 0:? 'color' (in 3-element array of 4-component vector of float) 0:? 'color2' (in 3-element array of 4-component vector of float) 0:? 'colorS' (in 3-element array of 4-component vector of float) diff --git a/Test/baseResults/410.geom.out b/Test/baseResults/410.geom.out index 13bd5f96..f1c1d0a7 100644 --- a/Test/baseResults/410.geom.out +++ b/Test/baseResults/410.geom.out @@ -1,11 +1,13 @@ 410.geom Warning, version 410 is not yet complete; some version-specific features are present, but many are missing. ERROR: 0:8: 'myIn' : cannot redeclare a built-in block with a user name -ERROR: 0:8: 'gl_' : reserved built-in name -ERROR: 0:12: 'gl_' : reserved built-in name +ERROR: 0:12: 'gl_myIn' : no declaration found for redeclaration ERROR: 0:20: 'gl_PerVertex' : can only redeclare a built-in block once, and before any use -ERROR: 0:20: 'gl_' : reserved built-in name -ERROR: 5 compilation errors. No code generated. +ERROR: 0:32: 'gl_Position' : no such field in structure +ERROR: 0:32: '=' : cannot convert from 'block{gl_PointSize}' to '4-component vector of float' +ERROR: 0:33: 'gl_Position' : member of nameless block was not redeclared +ERROR: 0:33: 'assign' : cannot convert from 'const 4-component vector of float' to 'layout(stream=0 ) gl_Position void' +ERROR: 7 compilation errors. No code generated. invocations = 0 @@ -35,13 +37,17 @@ ERROR: node is still EOpNull! 0:30 0 (const int) 0:31 move second child to first child (float) 0:31 gl_PointSize: direct index for structure (layout(stream=0 ) gl_PointSize float) -0:31 '__anon__0' (layout(stream=0 ) out block{gl_PointSize}) +0:31 '__anon__0' (layout(stream=0 ) out block{gl_PointSize,}) 0:31 Constant: -0:31 0 (const uint) +0:31 1 (const uint) 0:31 'p' (float) +0:33 gl_Position: direct index for structure (layout(stream=0 ) gl_Position void) +0:33 '__anon__0' (layout(stream=0 ) out block{gl_PointSize,}) +0:33 Constant: +0:33 0 (const uint) 0:? Linker Objects 0:? 'gl_in' (in unsized array of block{gl_PointSize}) -0:? '__anon__0' (layout(stream=0 ) out block{gl_PointSize}) +0:? '__anon__0' (layout(stream=0 ) out block{gl_PointSize,}) Linked geometry stage: diff --git a/Test/baseResults/420.geom.out b/Test/baseResults/420.geom.out index f05e2c83..2246a11c 100644 --- a/Test/baseResults/420.geom.out +++ b/Test/baseResults/420.geom.out @@ -4,7 +4,9 @@ ERROR: 0:9: 'length' : array must be declared with a size before using this met ERROR: 0:11: '[' : array must be redeclared with a size before being indexed with a variable ERROR: 0:42: 'assign' : l-value required (can't modify a const) ERROR: 0:43: 'assign' : l-value required "v4" (can't modify a uniform) -ERROR: 4 compilation errors. No code generated. +ERROR: 0:48: 'gl_PointSize' : cannot change arrayness of redeclared block member +ERROR: 0:49: 'gl_ClipDistance' : cannot change arrayness of redeclared block member +ERROR: 6 compilation errors. No code generated. invocations = 0 @@ -115,6 +117,7 @@ ERROR: node is still EOpNull! 0:? 's2D' (uniform sampler2D) 0:? 'coord' (in 2-component vector of float) 0:? 'v4' (uniform 4-component vector of float) +0:? '__anon__0' (layout(stream=0 ) out block{gl_PointSize,gl_ClipDistance}) Linked geometry stage: diff --git a/Test/baseResults/420.vert.out b/Test/baseResults/420.vert.out index 494a9bda..b7f239e2 100644 --- a/Test/baseResults/420.vert.out +++ b/Test/baseResults/420.vert.out @@ -130,6 +130,7 @@ ERROR: node is still EOpNull! 0:? 'sampb3' (layout(binding=32 ) uniform sampler2D) 0:? 'sampb4' (layout(binding=31 ) uniform sampler2D) 0:? 'sampb5' (layout(binding=31 ) uniform 2-element array of sampler2D) +0:? '__anon__3' (out block{gl_ClipDistance,}) 0:? 'gl_VertexID' (gl_VertexId int) 0:? 'gl_InstanceID' (gl_InstanceId int) diff --git a/Test/baseResults/430.vert.out b/Test/baseResults/430.vert.out index 486d0c00..3b347df5 100644 --- a/Test/baseResults/430.vert.out +++ b/Test/baseResults/430.vert.out @@ -23,9 +23,9 @@ ERROR: node is still EOpNull! 0:16 move second child to first child (float) 0:16 direct index (float) 0:16 gl_ClipDistance: direct index for structure (17-element array of float) -0:16 '__anon__0' (out block{gl_ClipDistance}) +0:16 '__anon__0' (out block{gl_ClipDistance,}) 0:16 Constant: -0:16 0 (const uint) +0:16 2 (const uint) 0:16 Constant: 0:16 2 (const int) 0:16 Constant: @@ -41,7 +41,7 @@ ERROR: node is still EOpNull! 0:? 'uv4' (layout(location=4 ) uniform 4-component vector of float) 0:? 'b1' (layout(location=2 ) in block{v}) 0:? 'b2' (layout(location=2 ) out block{v}) -0:? '__anon__0' (out block{gl_ClipDistance}) +0:? '__anon__0' (out block{gl_ClipDistance,}) 0:? 'cs' (layout(location=10 ) smooth out 2-element array of structure{m,f}) 0:? 'cf' (layout(location=54 ) smooth out float) 0:? 'cg' (layout(location=53 ) smooth out float) diff --git a/Test/baseResults/decls.frag.out b/Test/baseResults/decls.frag.out index 5181b50d..63b85127 100644 --- a/Test/baseResults/decls.frag.out +++ b/Test/baseResults/decls.frag.out @@ -8,15 +8,15 @@ ERROR: 0:22: 'vn8' : illegal use of type 'void' ERROR: 0:22: 'vp' : illegal use of type 'void' ERROR: 0:25: 'cij' : variables with qualifier 'const' must be initialized ERROR: 0:27: 'cip' : variables with qualifier 'const' must be initialized -ERROR: 0:34: 'gl_' : reserved built-in name -ERROR: 0:35: 'gl_' : reserved built-in name -ERROR: 0:35: 'gl_' : reserved built-in name -ERROR: 0:36: 'gl_' : reserved built-in name -ERROR: 0:36: 'gl_' : reserved built-in name -ERROR: 0:37: 'gl_' : reserved built-in name -ERROR: 0:37: 'gl_' : reserved built-in name +ERROR: 0:34: 'gl_' : reserved built-in name: gl_vi4 +ERROR: 0:35: 'gl_' : reserved built-in name: gl_vj +ERROR: 0:35: 'gl_' : reserved built-in name: gl_vk5 +ERROR: 0:36: 'gl_' : reserved built-in name: gl_vm2 +ERROR: 0:36: 'gl_' : reserved built-in name: gl_vm3 +ERROR: 0:37: 'gl_' : reserved built-in name: gl_vn8 +ERROR: 0:37: 'gl_' : reserved built-in name: gl_vp ERROR: 0:42: '' : boolean expression expected -ERROR: 0:43: 'gl_' : reserved built-in name +ERROR: 0:43: 'gl_' : reserved built-in name: gl_cond ERROR: 18 compilation errors. No code generated. diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index 7ee79554..c5b7bad3 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -828,9 +828,11 @@ public: if (structure) { s.append("{"); for (size_t i = 0; i < structure->size(); ++i) { - s.append((*structure)[i].type->getFieldName()); - if (i < structure->size()-1) - s.append(","); + if ((*structure)[i].type->getBasicType() != EbtVoid) { + s.append((*structure)[i].type->getFieldName()); + if (i < structure->size() - 1) + s.append(","); + } } s.append("}"); } diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h index 85375b63..5982b3fc 100644 --- a/glslang/Include/revision.h +++ b/glslang/Include/revision.h @@ -9,5 +9,5 @@ // source have to figure out how to create revision.h just to get a build // going. However, if it is not updated, it can be a version behind. -#define GLSLANG_REVISION "24397" -#define GLSLANG_DATE "2013/12/06 16:57:42" +#define GLSLANG_REVISION "24400" +#define GLSLANG_DATE "2013/12/06 17:28:07" diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 2b77f215..e102b51c 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -376,6 +376,8 @@ TIntermTyped* TParseContext::handleVariable(TSourceLoc loc, TSymbol* symbol, TSt node = intermediate.addIndex(EOpIndexDirectStruct, container, constNode, loc); node->setType(*(*variable->getType().getStruct())[anon->getMemberNumber()].type); + if (node->getBasicType() == EbtVoid) + error(loc, "member of nameless block was not redeclared", string->c_str(), ""); if (variable->getType().getQualifier().isIo()) noteAccess = true; @@ -1375,22 +1377,14 @@ void TParseContext::globalCheck(TSourceLoc loc, const char* token) // Except, if the symbol table is at a built-in level, // which is when we are parsing built-ins. // -bool TParseContext::reservedErrorCheck(TSourceLoc loc, const TString& identifier) +void TParseContext::reservedErrorCheck(TSourceLoc loc, const TString& identifier) { if (! symbolTable.atBuiltInLevel()) { - if (builtInName(identifier)) { - error(loc, "reserved built-in name", "gl_", ""); - - return true; - } - if (identifier.find("__") != TString::npos) { + if (builtInName(identifier)) + error(loc, "reserved built-in name:", "gl_", identifier.c_str()); + if (identifier.find("__") != TString::npos) error(loc, "Two consecutive underscores are reserved for future use.", identifier.c_str(), "", ""); - - return true; - } } - - return false; } // @@ -1992,10 +1986,7 @@ void TParseContext::declareArray(TSourceLoc loc, TString& identifier, const TTyp return; } - if (identifier.compare("gl_TexCoord") == 0) - limitCheck(loc, type.getArraySize(), "gl_MaxTextureCoords", "gl_TexCoord array size"); - else if (identifier.compare("gl_ClipDistance") == 0) - limitCheck(loc, type.getArraySize(), "gl_MaxClipDistances", "gl_ClipDistance array size"); + arrayLimitCheck(loc, identifier, type.getArraySize()); newType.shareArraySizes(type); @@ -2164,24 +2155,27 @@ TSymbol* TParseContext::redeclareBuiltinVariable(TSourceLoc loc, const TString& return 0; } -bool TParseContext::redeclareBuiltinBlock(TSourceLoc loc, TTypeList& typeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes) +// +// Either redeclare the requested block, or give an error message why it can't be done. +// +void TParseContext::redeclareBuiltinBlock(TSourceLoc loc, TTypeList& newTypeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes) { - // just a quick out, not everything that must be checked: - if (symbolTable.atBuiltInLevel() || profile == EEsProfile || ! builtInName(blockName)) - return false; + const char* feature = "built-in block redeclaration"; + requireProfile(loc, ECoreProfile | ECompatibilityProfile, feature); + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 410, GL_ARB_separate_shader_objects, feature); + + if (blockName != "gl_PerVertex" && blockName != "gl_PerFragment") { + error(loc, "cannot redeclare block: ", "block declaration", blockName.c_str()); + return; + } + + // Redeclaring a built-in block... if (instanceName && ! builtInName(*instanceName)) { error(loc, "cannot redeclare a built-in block with a user name", instanceName->c_str(), ""); - return false; + return; } - profileRequires(loc, ECoreProfile | ECompatibilityProfile, 410, GL_ARB_separate_shader_objects, "built-in block redeclaration"); - - // Potentially redeclaring a built-in block... - - if (blockName != "gl_PerVertex" && blockName != "gl_PerFragment") - return false; - // Blocks with instance names are easy to find, lookup the instance name, // Anonymous blocks need to be found via a member. bool builtIn; @@ -2189,64 +2183,110 @@ bool TParseContext::redeclareBuiltinBlock(TSourceLoc loc, TTypeList& typeList, c if (instanceName) block = symbolTable.find(*instanceName, &builtIn); else - block = symbolTable.find(typeList.front().type->getFieldName(), &builtIn); + block = symbolTable.find(newTypeList.front().type->getFieldName(), &builtIn); // If the block was not found, this must be a version/profile/stage - // that doesn't have it. - if (! block) - return false; - + // that doesn't have it, or the instance name is wrong. + const char* errorName = instanceName ? instanceName->c_str() : newTypeList.front().type->getFieldName().c_str(); + if (! block) { + error(loc, "no declaration found for redeclaration", errorName, ""); + return; + } // Built-in blocks cannot be redeclared more than once, which if happened, // we'd be finding the already redeclared one here, rather than the built in. if (! builtIn) { error(loc, "can only redeclare a built-in block once, and before any use", blockName.c_str(), ""); - return false; + return; } // Copy the block to make a writable version, to insert into the block table after editing. block = symbolTable.copyUpDeferredInsert(block); if (block->getType().getBasicType() != EbtBlock) { - error(loc, "cannot redeclare a non block as a block", blockName.c_str(), ""); - return false; + error(loc, "cannot redeclare a non block as a block", errorName, ""); + return; } // Handle geometry shader input arrays: see inputArrayNodeResizeList comment in ParseHelper.h if (language == EShLangGeometry && block->getType().isArray() && block->getType().getQualifier().storage == EvqVaryingIn) inputArraySymbolResizeList.push_back(block); - // TODO: SSO/4.10 semantics: block redeclaration: instance array size matching - // Edit and error check the container against the redeclaration // - remove unused members - // - ensure remaining qualifiers match + // - ensure remaining qualifiers/types match TType& type = block->getWritableType(); TTypeList::iterator member = type.getStruct()->begin(); + size_t numOriginalMembersFound = 0; while (member != type.getStruct()->end()) { // look for match bool found = false; - for (TTypeList::iterator newMember = typeList.begin(); newMember != typeList.end(); ++newMember) { + TTypeList::iterator newMember; + TSourceLoc memberLoc; + for (newMember = newTypeList.begin(); newMember != newTypeList.end(); ++newMember) { if (member->type->getFieldName() == newMember->type->getFieldName()) { found = true; + memberLoc = newMember->loc; break; } } - // remove non-redeclared members - if (found) - ++member; - else - member = type.getStruct()->erase(member); + if (found) { + ++numOriginalMembersFound; + // - ensure match between redeclared members' types + // - check for things that can't be changed + // - update things that can be changed + TType& oldType = *member->type; + const TType& newType = *newMember->type; + if (! newType.sameElementType(oldType)) + error(memberLoc, "cannot redeclare block member with a different type", member->type->getFieldName().c_str(), ""); + if (oldType.isArray() != newType.isArray()) + error(memberLoc, "cannot change arrayness of redeclared block member", member->type->getFieldName().c_str(), ""); + else if (! oldType.sameArrayness(newType) && oldType.getArraySize() > 0) + error(memberLoc, "cannot change array size of redeclared block member", member->type->getFieldName().c_str(), ""); + else if (newType.isArray()) + arrayLimitCheck(loc, member->type->getFieldName(), newType.getArraySize()); + if (newType.getQualifier().isMemory()) + error(memberLoc, "cannot add memory qualifier to redeclared block member", member->type->getFieldName().c_str(), ""); + if (newType.getQualifier().hasLayout()) + error(memberLoc, "cannot add layout to redeclared block member", member->type->getFieldName().c_str(), ""); + if (newType.getQualifier().patch) + error(memberLoc, "cannot add patch to redeclared block member", member->type->getFieldName().c_str(), ""); + oldType.getQualifier().centroid = newType.getQualifier().centroid; + oldType.getQualifier().sample = newType.getQualifier().sample; + oldType.getQualifier().invariant = newType.getQualifier().invariant; + oldType.getQualifier().smooth = newType.getQualifier().smooth; + oldType.getQualifier().flat = newType.getQualifier().flat; + oldType.getQualifier().nopersp = newType.getQualifier().nopersp; - // TODO: SSO/4.10 semantics: block redeclaration: member type/qualifier matching + // go to next member + ++member; + } else { + // Use EbtVoid to tag missing members of anonymous blocks that have been redeclared, + // to hide the original (shared) declaration. + // (Instance-named blocks can just have the member removed.) + if (instanceName) + member = type.getStruct()->erase(member); + else { + member->type->setElementType(EbtVoid, 1, 0, 0, 0); + ++member; + } + } } + if (numOriginalMembersFound < newTypeList.size()) + error(loc, "block redeclaration has extra members", blockName.c_str(), ""); + if (type.isArray() != (arraySizes != 0)) + error(loc, "cannot change arrayness of redeclared block", blockName.c_str(), ""); + else if (type.isArray() && type.getArraySize() > 0 && type.getArraySize() != arraySizes->getSize()) + error(loc, "cannot change array size of redeclared block", blockName.c_str(), ""); + symbolTable.insert(*block); + // Check for general layout qualifier errors + layoutTypeCheck(loc, *block); + // Save it in the AST for linker use. intermediate.addSymbolLinkageNode(linkage, *block); - - return true; } void TParseContext::paramCheckFix(TSourceLoc loc, const TStorageQualifier& qualifier, TType& type) @@ -2451,6 +2491,15 @@ void TParseContext::inductiveLoopCheck(TSourceLoc loc, TIntermNode* init, TInter inductiveLoopBodyCheck(loop->getBody(), loopIndex, symbolTable); } +// Do limit checks against for all built-in arrays. +void TParseContext::arrayLimitCheck(TSourceLoc loc, const TString& identifier, int size) +{ + if (identifier.compare("gl_TexCoord") == 0) + limitCheck(loc, size, "gl_MaxTextureCoords", "gl_TexCoord array size"); + else if (identifier.compare("gl_ClipDistance") == 0) + limitCheck(loc, size, "gl_MaxClipDistances", "gl_ClipDistance array size"); +} + // See if the provide value is less than the symbol indicated by limit, // which should be a constant in the symbol table. void TParseContext::limitCheck(TSourceLoc loc, int value, const char* limit, const char* feature) @@ -3348,18 +3397,6 @@ TIntermTyped* TParseContext::constructStruct(TIntermNode* node, const TType& typ // void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TString* instanceName, TArraySizes* arraySizes) { - // This might be a redeclaration of a built-in block, find out, and get - // a modifiable copy if so. - if (redeclareBuiltinBlock(loc, typeList, *blockName, instanceName, arraySizes)) - return; - - // Basic error checks - if (reservedErrorCheck(loc, *blockName)) - return; - - if (instanceName && reservedErrorCheck(loc, *instanceName)) - return; - if (profile == EEsProfile && arraySizes) arraySizeRequiredCheck(loc, arraySizes->getSize()); @@ -3392,7 +3429,7 @@ void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TStr pipeInOutFix(memberLoc, memberQualifier); if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != currentBlockQualifier.storage) error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", typeList[member].type->getFieldName().c_str(), ""); - if ((currentBlockQualifier.storage == EvqUniform && memberQualifier.isInterpolation()) || memberQualifier.isAuxiliary()) + if (currentBlockQualifier.storage == EvqUniform && (memberQualifier.isInterpolation() || memberQualifier.isAuxiliary())) error(memberLoc, "member of uniform block cannot have an auxiliary or interpolation qualifier", typeList[member].type->getFieldName().c_str(), ""); TBasicType basicType = typeList[member].type->getBasicType(); @@ -3400,6 +3437,20 @@ void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TStr error(memberLoc, "member of block cannot be a sampler type", typeList[member].type->getFieldName().c_str(), ""); } + // This might be a redeclaration of a built-in block. If so, redeclareBuiltinBlock() will + // do all the rest. + if (! symbolTable.atBuiltInLevel() && builtInName(*blockName)) { + redeclareBuiltinBlock(loc, typeList, *blockName, instanceName, arraySizes); + return; + } + + // Not a redeclaration of a built-in; check that all names are user names. + reservedErrorCheck(loc, *blockName); + if (instanceName) + reservedErrorCheck(loc, *instanceName); + for (unsigned int member = 0; member < typeList.size(); ++member) + reservedErrorCheck(typeList[member].loc, typeList[member].type->getFieldName()); + // Make default block qualification, and adjust the member qualifications TQualifier defaultQualification; @@ -3427,14 +3478,14 @@ void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TStr memberQualifier = newMemberQualification; } - // - // Build and add the interface block as a new type named blockName - // - // reverse merge, so that currentBlockQualifier now has all layout information // (can't use defaultQualification directly, it's missing other non-layout-default-class qualifiers) mergeObjectLayoutQualifiers(loc, currentBlockQualifier, defaultQualification); + // + // Build and add the interface block as a new type named 'blockName' + // + TType blockType(&typeList, *blockName, currentBlockQualifier); if (arraySizes) blockType.setArraySizes(arraySizes); diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index f4c0fc21..54144701 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -74,7 +74,7 @@ public: const char *szExtraInfoFormat, ...); void C_DECL warn(TSourceLoc, const char *szReason, const char *szToken, const char *szExtraInfoFormat, ...); - bool reservedErrorCheck(TSourceLoc, const TString&); + void reservedErrorCheck(TSourceLoc, const TString&); void reservedPpErrorCheck(TSourceLoc, const char* name, const char* op); bool lineContinuationCheck(TSourceLoc, bool endOfComment); bool builtInName(const TString&); @@ -125,7 +125,7 @@ public: void parameterSamplerCheck(TSourceLoc, TStorageQualifier qualifier, const TType& type); 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 redeclareBuiltinBlock(TSourceLoc, TTypeList& typeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes); void paramCheckFix(TSourceLoc, const TStorageQualifier&, TType& type); void paramCheckFix(TSourceLoc, const TQualifier&, TType& type); void nestedBlockCheck(TSourceLoc); @@ -134,6 +134,7 @@ public: void opaqueCheck(TSourceLoc, const TType&, const char* op); void structTypeCheck(TSourceLoc, TPublicType&); void inductiveLoopCheck(TSourceLoc, TIntermNode* init, TIntermLoop* loop); + void arrayLimitCheck(TSourceLoc, const TString&, int size); void limitCheck(TSourceLoc, int value, const char* limit, const char* feature); void inductiveLoopBodyCheck(TIntermNode*, int loopIndexId, TSymbolTable&);