Add semantic checks for nested blocks/structures.
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@21960 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
parent
fd8e101072
commit
3da5a3267e
@ -44,7 +44,7 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, int v, E
|
|||||||
bool fc, EShMessages m) :
|
bool fc, EShMessages m) :
|
||||||
intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0),
|
intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0),
|
||||||
numErrors(0), lexAfterType(false), loopNestingLevel(0),
|
numErrors(0), lexAfterType(false), loopNestingLevel(0),
|
||||||
inTypeParen(false),
|
structNestingLevel(0), inTypeParen(false),
|
||||||
version(v), profile(p), forwardCompatible(fc), messages(m),
|
version(v), profile(p), forwardCompatible(fc), messages(m),
|
||||||
contextPragma(true, false)
|
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.
|
// Layout qualifier stuff.
|
||||||
//
|
//
|
||||||
@ -1449,26 +1463,26 @@ TIntermTyped* TParseContext::constructStruct(TIntermNode* node, const TType& typ
|
|||||||
//
|
//
|
||||||
// Do everything needed to add an interface block.
|
// 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
|
// First, error checks
|
||||||
|
|
||||||
if (reservedErrorCheck(line, blockName))
|
if (reservedErrorCheck(line, *blockName))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (instanceName && reservedErrorCheck(line, *instanceName))
|
if (instanceName && reservedErrorCheck(line, *instanceName))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (publicType.basicType != EbtVoid) {
|
if (blockType.basicType != EbtVoid) {
|
||||||
error(line, "interface blocks cannot be declared with a type", blockName.c_str(), "");
|
error(line, "interface blocks cannot be declared with a type", blockName->c_str(), "");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (publicType.qualifier.storage == EvqUniform) {
|
if (blockType.qualifier.storage == EvqUniform) {
|
||||||
requireProfile(line, (EProfileMask)(~ENoProfileMask), "uniform block");
|
requireProfile(line, (EProfileMask)(~ENoProfileMask), "uniform block");
|
||||||
profileRequires(line, EEsProfile, 300, 0, "uniform block");
|
profileRequires(line, EEsProfile, 300, 0, "uniform block");
|
||||||
} else {
|
} else {
|
||||||
error(line, "only uniform interface blocks are supported", blockName.c_str(), "");
|
error(line, "only uniform interface blocks are supported", blockName->c_str(), "");
|
||||||
|
|
||||||
return;
|
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
|
// check for qualifiers and types that don't belong within a block
|
||||||
for (unsigned int member = 0; member < typeList.size(); ++member) {
|
for (unsigned int member = 0; member < typeList.size(); ++member) {
|
||||||
TQualifier memberQualifier = typeList[member].type->getQualifier();
|
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(), "");
|
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(), "");
|
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();
|
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
|
// Make default block qualification, and adjust the member qualifications
|
||||||
|
|
||||||
TQualifier defaultQualification = defaultGlobalQualification;
|
TQualifier defaultQualification = defaultGlobalQualification;
|
||||||
mergeLayoutQualifiers(line, defaultQualification, publicType.qualifier);
|
mergeLayoutQualifiers(line, defaultQualification, blockType.qualifier);
|
||||||
for (unsigned int member = 0; member < typeList.size(); ++member) {
|
for (unsigned int member = 0; member < typeList.size(); ++member) {
|
||||||
TQualifier memberQualification = defaultQualification;
|
TQualifier memberQualification = defaultQualification;
|
||||||
mergeLayoutQualifiers(line, memberQualification, typeList[member].type->getQualifier());
|
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
|
// 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)
|
if (arraySizes)
|
||||||
blockType.setArraySizes(arraySizes);
|
blockType.setArraySizes(arraySizes);
|
||||||
blockType.getQualifier().layoutPacking = defaultQualification.layoutPacking;
|
blockType.getQualifier().layoutPacking = defaultQualification.layoutPacking;
|
||||||
TVariable* userTypeDef = new TVariable(&blockName, blockType, true);
|
TVariable* userTypeDef = new TVariable(blockName, blockType, true);
|
||||||
if (! symbolTable.insert(*userTypeDef)) {
|
if (! symbolTable.insert(*userTypeDef)) {
|
||||||
error(line, "redefinition", blockName.c_str(), "block name");
|
error(line, "redefinition", blockName->c_str(), "block name");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1518,7 +1532,7 @@ void TParseContext::addBlock(int line, TPublicType& publicType, const TString& b
|
|||||||
TVariable* variable = new TVariable(instanceName, blockType);
|
TVariable* variable = new TVariable(instanceName, blockType);
|
||||||
if (! symbolTable.insert(*variable)) {
|
if (! symbolTable.insert(*variable)) {
|
||||||
if (*instanceName == "")
|
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
|
else
|
||||||
error(line, "block instance name redefinition", variable->getName().c_str(), "");
|
error(line, "block instance name redefinition", variable->getName().c_str(), "");
|
||||||
|
|
||||||
|
@ -77,6 +77,7 @@ struct TParseContext {
|
|||||||
int numErrors; // number of compile-time errors encountered
|
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
|
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 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
|
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
|
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
|
const TType* currentFunctionType; // the return type of the function that's currently being parsed
|
||||||
@ -93,6 +94,8 @@ struct TParseContext {
|
|||||||
TQualifier defaultGlobalQualification;
|
TQualifier defaultGlobalQualification;
|
||||||
TString HashErrMsg;
|
TString HashErrMsg;
|
||||||
bool AfterEOF;
|
bool AfterEOF;
|
||||||
|
const TString* blockName;
|
||||||
|
TPublicType blockType;
|
||||||
|
|
||||||
void initializeExtensionBehavior();
|
void initializeExtensionBehavior();
|
||||||
const char* getPreamble();
|
const char* getPreamble();
|
||||||
@ -130,6 +133,8 @@ struct TParseContext {
|
|||||||
void nonInitConstCheck(int line, TString& identifier, TPublicType& type);
|
void nonInitConstCheck(int line, TString& identifier, TPublicType& type);
|
||||||
void nonInitCheck(int line, TString& identifier, TPublicType& type);
|
void nonInitCheck(int line, TString& identifier, TPublicType& type);
|
||||||
void paramCheck(int line, TStorageQualifier qualifier, TType* 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&);
|
||||||
void setLayoutQualifier(int line, TPublicType&, TString&, int);
|
void setLayoutQualifier(int line, TPublicType&, TString&, int);
|
||||||
@ -141,7 +146,7 @@ struct TParseContext {
|
|||||||
TIntermTyped* addConstructor(TIntermNode*, const TType&, TOperator, TFunction*, TSourceLoc);
|
TIntermTyped* addConstructor(TIntermNode*, const TType&, TOperator, TFunction*, TSourceLoc);
|
||||||
TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc);
|
TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc);
|
||||||
TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermNode*, TSourceLoc, bool subset);
|
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);
|
void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode);
|
||||||
TIntermNode* addSwitch(int line, TIntermTyped* expression, TIntermAggregate* body);
|
TIntermNode* addSwitch(int line, TIntermTyped* expression, TIntermAggregate* body);
|
||||||
void updateDefaults(int line, const TPublicType&, const TString* id);
|
void updateDefaults(int line, const TPublicType&, const TString* id);
|
||||||
|
@ -208,6 +208,7 @@ extern void yyerror(const char*);
|
|||||||
%type <interm.type> struct_specifier
|
%type <interm.type> struct_specifier
|
||||||
%type <interm.typeLine> struct_declarator
|
%type <interm.typeLine> struct_declarator
|
||||||
%type <interm.typeList> struct_declarator_list struct_declaration struct_declaration_list type_name_list
|
%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 function_declarator
|
||||||
%type <interm.function> function_header_with_parameters
|
%type <interm.function> function_header_with_parameters
|
||||||
%type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype
|
%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);
|
parseContext.setDefaultPrecision($1.line, $3, $2.qualifier.precision);
|
||||||
$$ = 0;
|
$$ = 0;
|
||||||
}
|
}
|
||||||
| type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE SEMICOLON {
|
| block_structure SEMICOLON {
|
||||||
parseContext.addBlock($2.line, $1, *$2.string, *$4);
|
parseContext.addBlock($1.line, *$1.typeList);
|
||||||
$$ = 0;
|
$$ = 0;
|
||||||
}
|
}
|
||||||
| type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON {
|
| block_structure IDENTIFIER SEMICOLON {
|
||||||
parseContext.addBlock($2.line, $1, *$2.string, *$4, $6.string);
|
parseContext.addBlock($1.line, *$1.typeList, $2.string);
|
||||||
$$ = 0;
|
$$ = 0;
|
||||||
}
|
}
|
||||||
| type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE IDENTIFIER array_specifier SEMICOLON {
|
| block_structure IDENTIFIER array_specifier SEMICOLON {
|
||||||
parseContext.addBlock($2.line, $1, *$2.string, *$4, $6.string, $7.arraySizes);
|
parseContext.addBlock($1.line, *$1.typeList, $2.string, $3.arraySizes);
|
||||||
$$ = 0;
|
$$ = 0;
|
||||||
}
|
}
|
||||||
| type_qualifier SEMICOLON {
|
| 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
|
identifier_list
|
||||||
: COMMA IDENTIFIER {
|
: COMMA IDENTIFIER {
|
||||||
}
|
}
|
||||||
@ -2397,25 +2407,22 @@ precision_qualifier
|
|||||||
;
|
;
|
||||||
|
|
||||||
struct_specifier
|
struct_specifier
|
||||||
: STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE {
|
: STRUCT IDENTIFIER LEFT_BRACE { parseContext.nestedStructCheck($1.line); } struct_declaration_list RIGHT_BRACE {
|
||||||
// TODO: semantics: check for qualifiers that don't belong in a struct
|
TType* structure = new TType($5, *$2.string);
|
||||||
|
|
||||||
// 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);
|
|
||||||
TVariable* userTypeDef = new TVariable($2.string, *structure, true);
|
TVariable* userTypeDef = new TVariable($2.string, *structure, true);
|
||||||
if (! parseContext.symbolTable.insert(*userTypeDef))
|
if (! parseContext.symbolTable.insert(*userTypeDef))
|
||||||
parseContext.error($2.line, "redefinition", $2.string->c_str(), "struct");
|
parseContext.error($2.line, "redefinition", $2.string->c_str(), "struct");
|
||||||
$$.init($1.line);
|
$$.init($1.line);
|
||||||
$$.basicType = EbtStruct;
|
$$.basicType = EbtStruct;
|
||||||
$$.userDef = structure;
|
$$.userDef = structure;
|
||||||
|
--parseContext.structNestingLevel;
|
||||||
}
|
}
|
||||||
| STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE {
|
| STRUCT LEFT_BRACE { parseContext.nestedStructCheck($1.line); } struct_declaration_list RIGHT_BRACE {
|
||||||
TType* structure = new TType($3, TString(""));
|
TType* structure = new TType($4, TString(""));
|
||||||
$$.init($1.line);
|
$$.init($1.line);
|
||||||
$$.basicType = EbtStruct;
|
$$.basicType = EbtStruct;
|
||||||
$$.userDef = structure;
|
$$.userDef = structure;
|
||||||
|
--parseContext.structNestingLevel;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user