diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 45a16896e1053e6ae18c08179c7e6109bd6cfd85..01f3a9f264a1b4928b78d630237564a3cce72996 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -44,7 +44,7 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, int v, E bool fc, EShMessages m) : intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0), numErrors(0), lexAfterType(false), loopNestingLevel(0), - inTypeParen(false), + structNestingLevel(0), inTypeParen(false), version(v), profile(p), forwardCompatible(fc), messages(m), contextPragma(true, false) { @@ -1072,6 +1072,20 @@ void TParseContext::paramCheck(int line, TStorageQualifier qualifier, TType* typ } } +void TParseContext::nestedBlockCheck(int line) +{ + if (structNestingLevel > 0) + error(line, "cannot nest a block definition inside a structure or block", "", ""); + ++structNestingLevel; +} + +void TParseContext::nestedStructCheck(int line) +{ + if (structNestingLevel > 0) + error(line, "cannot nest a structure definition inside a structure or block", "", ""); + ++structNestingLevel; +} + // // Layout qualifier stuff. // @@ -1449,26 +1463,26 @@ TIntermTyped* TParseContext::constructStruct(TIntermNode* node, const TType& typ // // Do everything needed to add an interface block. // -void TParseContext::addBlock(int line, TPublicType& publicType, const TString& blockName, TTypeList& typeList, const TString* instanceName, TArraySizes arraySizes) +void TParseContext::addBlock(int line, TTypeList& typeList, const TString* instanceName, TArraySizes arraySizes) { // First, error checks - if (reservedErrorCheck(line, blockName)) + if (reservedErrorCheck(line, *blockName)) return; if (instanceName && reservedErrorCheck(line, *instanceName)) return; - if (publicType.basicType != EbtVoid) { - error(line, "interface blocks cannot be declared with a type", blockName.c_str(), ""); + if (blockType.basicType != EbtVoid) { + error(line, "interface blocks cannot be declared with a type", blockName->c_str(), ""); return; } - if (publicType.qualifier.storage == EvqUniform) { + if (blockType.qualifier.storage == EvqUniform) { requireProfile(line, (EProfileMask)(~ENoProfileMask), "uniform block"); profileRequires(line, EEsProfile, 300, 0, "uniform block"); } else { - error(line, "only uniform interface blocks are supported", blockName.c_str(), ""); + error(line, "only uniform interface blocks are supported", blockName->c_str(), ""); return; } @@ -1476,9 +1490,9 @@ void TParseContext::addBlock(int line, TPublicType& publicType, const TString& b // check for qualifiers and types that don't belong within a block for (unsigned int member = 0; member < typeList.size(); ++member) { TQualifier memberQualifier = typeList[member].type->getQualifier(); - if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != publicType.qualifier.storage) + if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != blockType.qualifier.storage) error(line, "member storage qualifier cannot contradict block storage qualifier", typeList[member].type->getFieldName().c_str(), ""); - if (publicType.qualifier.storage == EvqUniform && memberQualifier.isInterpolation() || memberQualifier.isAuxillary()) + if (blockType.qualifier.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(), ""); TBasicType basicType = typeList[member].type->getBasicType(); @@ -1489,7 +1503,7 @@ void TParseContext::addBlock(int line, TPublicType& publicType, const TString& b // Make default block qualification, and adjust the member qualifications TQualifier defaultQualification = defaultGlobalQualification; - mergeLayoutQualifiers(line, defaultQualification, publicType.qualifier); + mergeLayoutQualifiers(line, defaultQualification, blockType.qualifier); for (unsigned int member = 0; member < typeList.size(); ++member) { TQualifier memberQualification = defaultQualification; mergeLayoutQualifiers(line, memberQualification, typeList[member].type->getQualifier()); @@ -1498,13 +1512,13 @@ void TParseContext::addBlock(int line, TPublicType& publicType, const TString& b // Build and add the interface block as a new type named blockName - TType blockType(&typeList, blockName, publicType.qualifier.storage); + TType blockType(&typeList, *blockName, blockType.qualifier.storage); if (arraySizes) blockType.setArraySizes(arraySizes); blockType.getQualifier().layoutPacking = defaultQualification.layoutPacking; - TVariable* userTypeDef = new TVariable(&blockName, blockType, true); + TVariable* userTypeDef = new TVariable(blockName, blockType, true); if (! symbolTable.insert(*userTypeDef)) { - error(line, "redefinition", blockName.c_str(), "block name"); + error(line, "redefinition", blockName->c_str(), "block name"); return; } @@ -1518,7 +1532,7 @@ void TParseContext::addBlock(int line, TPublicType& publicType, const TString& b TVariable* variable = new TVariable(instanceName, blockType); if (! symbolTable.insert(*variable)) { if (*instanceName == "") - error(line, "nameless block contains a member that already has a name at global scope", blockName.c_str(), ""); + error(line, "nameless block contains a member that already has a name at global scope", blockName->c_str(), ""); else error(line, "block instance name redefinition", variable->getName().c_str(), ""); diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index b5370a57b8a88cb8f151536850c0bdccce24a91d..e776a4adf14961ad6cc488033977f43b66a21a0f 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -77,6 +77,7 @@ struct TParseContext { int numErrors; // number of compile-time errors encountered bool lexAfterType; // true if we've recognized a type, so can only be looking for an identifier int loopNestingLevel; // 0 if outside all loops + int structNestingLevel; // 0 if outside blocks and structures TList<TIntermSequence*> switchSequenceStack; // case, node, case, case, node, ...; ensure only one node between cases; stack of them for nesting bool inTypeParen; // true if in parentheses, looking only for an identifier const TType* currentFunctionType; // the return type of the function that's currently being parsed @@ -93,6 +94,8 @@ struct TParseContext { TQualifier defaultGlobalQualification; TString HashErrMsg; bool AfterEOF; + const TString* blockName; + TPublicType blockType; void initializeExtensionBehavior(); const char* getPreamble(); @@ -130,6 +133,8 @@ struct TParseContext { void nonInitConstCheck(int line, TString& identifier, TPublicType& type); void nonInitCheck(int line, TString& identifier, TPublicType& type); void paramCheck(int line, TStorageQualifier qualifier, TType* type); + void nestedBlockCheck(int line); + void nestedStructCheck(int line); void setLayoutQualifier(int line, TPublicType&, TString&); void setLayoutQualifier(int line, TPublicType&, TString&, int); @@ -141,7 +146,7 @@ struct TParseContext { TIntermTyped* addConstructor(TIntermNode*, const TType&, TOperator, TFunction*, TSourceLoc); TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc); TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermNode*, TSourceLoc, bool subset); - void addBlock(int line, TPublicType& qualifier, const TString& blockName, TTypeList& typeList, const TString* instanceName = 0, TArraySizes arraySizes = 0); + void addBlock(int line, TTypeList& typeList, const TString* instanceName = 0, TArraySizes arraySizes = 0); void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode); TIntermNode* addSwitch(int line, TIntermTyped* expression, TIntermAggregate* body); void updateDefaults(int line, const TPublicType&, const TString* id); diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index 12e6ab92405fa4f33ded19c89642b0e115b5fd69..0dc84055ff15302d5219ccf9f55e344046d9e6bb 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -208,6 +208,7 @@ extern void yyerror(const char*); %type <interm.type> struct_specifier %type <interm.typeLine> struct_declarator %type <interm.typeList> struct_declarator_list struct_declaration struct_declaration_list type_name_list +%type <interm> block_structure %type <interm.function> function_header function_declarator %type <interm.function> function_header_with_parameters %type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype @@ -1102,16 +1103,16 @@ declaration parseContext.setDefaultPrecision($1.line, $3, $2.qualifier.precision); $$ = 0; } - | type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE SEMICOLON { - parseContext.addBlock($2.line, $1, *$2.string, *$4); + | block_structure SEMICOLON { + parseContext.addBlock($1.line, *$1.typeList); $$ = 0; } - | type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON { - parseContext.addBlock($2.line, $1, *$2.string, *$4, $6.string); + | block_structure IDENTIFIER SEMICOLON { + parseContext.addBlock($1.line, *$1.typeList, $2.string); $$ = 0; } - | type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE IDENTIFIER array_specifier SEMICOLON { - parseContext.addBlock($2.line, $1, *$2.string, *$4, $6.string, $7.arraySizes); + | block_structure IDENTIFIER array_specifier SEMICOLON { + parseContext.addBlock($1.line, *$1.typeList, $2.string, $3.arraySizes); $$ = 0; } | type_qualifier SEMICOLON { @@ -1130,6 +1131,15 @@ declaration } ; +block_structure + : type_qualifier IDENTIFIER LEFT_BRACE { parseContext.nestedBlockCheck($1.line); } struct_declaration_list RIGHT_BRACE { + --parseContext.structNestingLevel; + parseContext.blockName = $2.string; + parseContext.blockType = $1; + $$.line = $1.line; + $$.typeList = $5; + } + identifier_list : COMMA IDENTIFIER { } @@ -2397,25 +2407,22 @@ precision_qualifier ; struct_specifier - : STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE { - // TODO: semantics: check for qualifiers that don't belong in a struct - - // TODO: semantics: check that this is not nested inside a block or structure - // parseContext.error($1.line, "cannot nest a block or structure definitions", $1.userDef->getTypeName().c_str(), ""); - - TType* structure = new TType($4, *$2.string); + : STRUCT IDENTIFIER LEFT_BRACE { parseContext.nestedStructCheck($1.line); } struct_declaration_list RIGHT_BRACE { + TType* structure = new TType($5, *$2.string); TVariable* userTypeDef = new TVariable($2.string, *structure, true); if (! parseContext.symbolTable.insert(*userTypeDef)) parseContext.error($2.line, "redefinition", $2.string->c_str(), "struct"); $$.init($1.line); $$.basicType = EbtStruct; $$.userDef = structure; + --parseContext.structNestingLevel; } - | STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE { - TType* structure = new TType($3, TString("")); + | STRUCT LEFT_BRACE { parseContext.nestedStructCheck($1.line); } struct_declaration_list RIGHT_BRACE { + TType* structure = new TType($4, TString("")); $$.init($1.line); $$.basicType = EbtStruct; $$.userDef = structure; + --parseContext.structNestingLevel; } ;