Commit 55bde916 by Olli Etuaho Committed by Jamie Madill

Parse array specifier with a separate grammar rule

This brings the grammar closer to the GLSL ES 3.10 spec. Some corner cases related to handling unsized arrays are fixed. BUG=angleproject:2125 TEST=angle_unittests, angle_end2end_tests Change-Id: I9bcf87b17b97da0e2ec2954d32037c272fde3080 Reviewed-on: https://chromium-review.googlesource.com/738233Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent f7480ad2
......@@ -1030,13 +1030,13 @@ bool TParseContext::checkIsValidTypeAndQualifierForArray(const TSourceLoc &index
// Enforce non-initializer type/qualifier rules.
void TParseContext::checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
const TString &identifier,
TPublicType *type)
TType *type)
{
ASSERT(type != nullptr);
if (type->qualifier == EvqConst)
if (type->getQualifier() == EvqConst)
{
// Make the qualifier make sense.
type->qualifier = EvqTemporary;
type->setQualifier(EvqTemporary);
// Generate informative error messages for ESSL1.
// In ESSL3 arrays and structures containing arrays can be constant.
......@@ -1053,10 +1053,9 @@ void TParseContext::checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
}
return;
}
if (type->isUnsizedArray())
{
error(line, "implicitly sized arrays need to be initialized", identifier.c_str());
}
// This will make the type sized if it isn't sized yet.
checkIsNotUnsizedArray(line, "implicitly sized arrays need to be initialized",
identifier.c_str(), type);
}
// Do some simple checks that are shared between all variable declarations,
......@@ -1253,10 +1252,9 @@ void TParseContext::atomicCounterQualifierErrorCheck(const TPublicType &publicTy
}
}
void TParseContext::emptyDeclarationErrorCheck(const TPublicType &publicType,
const TSourceLoc &location)
void TParseContext::emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location)
{
if (publicType.isUnsizedArray())
if (type.isUnsizedArray())
{
// ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an
// error. It is assumed that this applies to empty declarations as well.
......@@ -1317,9 +1315,9 @@ void TParseContext::nonEmptyDeclarationErrorCheck(const TPublicType &publicType,
{
// Valid uniform declarations can't be unsized arrays since uniforms can't be initialized.
// But invalid shaders may still reach here with an unsized array declaration.
if (!publicType.isUnsizedArray())
TType type(publicType);
if (!type.isUnsizedArray())
{
TType type(publicType);
checkUniformLocationInRange(identifierLocation, type.getLocationCount(),
publicType.layoutQualifier);
}
......@@ -1805,7 +1803,7 @@ TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location,
ASSERT(mGeometryShaderInputArraySize > 0u);
node = new TIntermSymbol(variable->getUniqueId(), variable->getName(), variableType);
node->getTypePointer()->setArraySize(0, mGeometryShaderInputArraySize);
node->getTypePointer()->sizeOutermostUnsizedArray(mGeometryShaderInputArraySize);
}
else
{
......@@ -1822,13 +1820,12 @@ TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location,
// Returns true on success.
bool TParseContext::executeInitializer(const TSourceLoc &line,
const TString &identifier,
const TPublicType &pType,
TType type,
TIntermTyped *initializer,
TIntermBinary **initNode)
{
ASSERT(initNode != nullptr);
ASSERT(*initNode == nullptr);
TType type = TType(pType);
TVariable *variable = nullptr;
if (type.isUnsizedArray())
......@@ -1943,7 +1940,8 @@ TIntermNode *TParseContext::addConditionInitializer(const TPublicType &pType,
{
checkIsScalarBool(loc, pType);
TIntermBinary *initNode = nullptr;
if (executeInitializer(loc, identifier, pType, initializer, &initNode))
TType type(pType);
if (executeInitializer(loc, identifier, type, initializer, &initNode))
{
// The initializer is valid. The init condition needs to have a node - either the
// initializer node, or a constant node in case the initialized variable is const and won't
......@@ -2315,7 +2313,7 @@ TIntermDeclaration *TParseContext::parseSingleDeclaration(
TIntermSymbol *symbol = nullptr;
if (emptyDeclaration)
{
emptyDeclarationErrorCheck(publicType, identifierOrTypeLocation);
emptyDeclarationErrorCheck(type, identifierOrTypeLocation);
// In most cases we don't need to create a symbol node for an empty declaration.
// But if the empty declaration is declaring a struct type, the symbol node will store that.
if (type.getBasicType() == EbtStruct)
......@@ -2331,7 +2329,7 @@ TIntermDeclaration *TParseContext::parseSingleDeclaration(
{
nonEmptyDeclarationErrorCheck(publicType, identifierOrTypeLocation);
checkCanBeDeclaredWithoutInitializer(identifierOrTypeLocation, identifier, &publicType);
checkCanBeDeclaredWithoutInitializer(identifierOrTypeLocation, identifier, &type);
if (IsAtomicCounter(publicType.getBasicType()))
{
......@@ -2359,35 +2357,34 @@ TIntermDeclaration *TParseContext::parseSingleDeclaration(
return declaration;
}
TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType,
TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(TPublicType &elementType,
const TSourceLoc &identifierLocation,
const TString &identifier,
const TSourceLoc &indexLocation,
TIntermTyped *indexExpression)
unsigned int arraySize)
{
mDeferredNonEmptyDeclarationErrorCheck = false;
declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier,
declarationQualifierErrorCheck(elementType.qualifier, elementType.layoutQualifier,
identifierLocation);
nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType);
nonEmptyDeclarationErrorCheck(elementType, identifierLocation);
checkIsValidTypeAndQualifierForArray(indexLocation, publicType);
checkIsValidTypeAndQualifierForArray(indexLocation, elementType);
TType arrayType(publicType);
TType arrayType(elementType);
arrayType.makeArray(arraySize);
if (indexExpression == nullptr)
if (IsGeometryShaderInput(mShaderType, elementType.qualifier))
{
if (IsGeometryShaderInput(mShaderType, publicType.qualifier))
if (arrayType.isUnsizedArray())
{
// Set size for the unsized geometry shader inputs if they are declared after a valid
// input primitive declaration.
if (mGeometryShaderInputPrimitiveType != EptUndefined)
{
ASSERT(mGeometryShaderInputArraySize > 0u);
arrayType.makeArray(mGeometryShaderInputArraySize);
arrayType.sizeOutermostUnsizedArray(mGeometryShaderInputArraySize);
}
else
{
......@@ -2402,27 +2399,17 @@ TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(TPublicType &publ
}
else
{
// Unsized array declarations are only allowed in declaring geometry shader inputs.
error(indexLocation, "Invalid unsized array declaration", "");
setGeometryShaderInputArraySize(arrayType.getOutermostArraySize(), indexLocation);
}
}
else
{
unsigned int size = checkIsValidArraySize(identifierLocation, indexExpression);
if (IsGeometryShaderInput(mShaderType, publicType.qualifier))
{
setGeometryShaderInputArraySize(size, indexLocation);
}
// Make the type an array even if size check failed.
// This ensures useless error messages regarding the variable's non-arrayness won't follow.
arrayType.makeArray(size);
checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &arrayType);
if (IsAtomicCounter(publicType.getBasicType()))
{
checkAtomicCounterOffsetIsNotOverlapped(publicType, kAtomicCounterArrayStride * size,
false, identifierLocation, arrayType);
}
if (IsAtomicCounter(elementType.getBasicType()))
{
checkAtomicCounterOffsetIsNotOverlapped(
elementType, kAtomicCounterArrayStride * arrayType.getArraySizeProduct(), false,
identifierLocation, arrayType);
}
TVariable *variable = nullptr;
......@@ -2458,7 +2445,8 @@ TIntermDeclaration *TParseContext::parseSingleInitDeclaration(const TPublicType
declaration->setLine(identifierLocation);
TIntermBinary *initNode = nullptr;
if (executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
TType type(publicType);
if (executeInitializer(identifierLocation, identifier, type, initializer, &initNode))
{
if (initNode)
{
......@@ -2469,35 +2457,25 @@ TIntermDeclaration *TParseContext::parseSingleInitDeclaration(const TPublicType
}
TIntermDeclaration *TParseContext::parseSingleArrayInitDeclaration(
TPublicType &publicType,
TPublicType &elementType,
const TSourceLoc &identifierLocation,
const TString &identifier,
const TSourceLoc &indexLocation,
TIntermTyped *indexExpression,
unsigned int arraySize,
const TSourceLoc &initLocation,
TIntermTyped *initializer)
{
mDeferredNonEmptyDeclarationErrorCheck = false;
declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier,
declarationQualifierErrorCheck(elementType.qualifier, elementType.layoutQualifier,
identifierLocation);
nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
nonEmptyDeclarationErrorCheck(elementType, identifierLocation);
checkIsValidTypeAndQualifierForArray(indexLocation, publicType);
checkIsValidTypeAndQualifierForArray(indexLocation, elementType);
TPublicType arrayType(publicType);
unsigned int size = 0u;
// If indexExpression is nullptr, then the array will eventually get its size implicitly from
// the initializer.
if (indexExpression != nullptr)
{
size = checkIsValidArraySize(identifierLocation, indexExpression);
}
// Make the type an array even if size check failed.
// This ensures useless error messages regarding the variable's non-arrayness won't follow.
arrayType.setArraySize(size);
TType arrayType(elementType);
arrayType.makeArray(arraySize);
TIntermDeclaration *declaration = new TIntermDeclaration();
declaration->setLine(identifierLocation);
......@@ -2586,10 +2564,10 @@ void TParseContext::parseDeclarator(TPublicType &publicType,
checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType);
TVariable *variable = nullptr;
TType type(publicType);
checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &type);
if (IsAtomicCounter(publicType.getBasicType()))
{
checkAtomicCounterOffsetIsNotOverlapped(publicType, kAtomicCounterSize, true,
......@@ -2605,35 +2583,35 @@ void TParseContext::parseDeclarator(TPublicType &publicType,
}
}
void TParseContext::parseArrayDeclarator(TPublicType &publicType,
void TParseContext::parseArrayDeclarator(TPublicType &elementType,
const TSourceLoc &identifierLocation,
const TString &identifier,
const TSourceLoc &arrayLocation,
TIntermTyped *indexExpression,
unsigned int arraySize,
TIntermDeclaration *declarationOut)
{
// If the declaration starting this declarator list was empty (example: int,), some checks were
// not performed.
if (mDeferredNonEmptyDeclarationErrorCheck)
{
nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
nonEmptyDeclarationErrorCheck(elementType, identifierLocation);
mDeferredNonEmptyDeclarationErrorCheck = false;
}
checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType);
checkDeclaratorLocationIsNotSpecified(identifierLocation, elementType);
if (checkIsValidTypeAndQualifierForArray(arrayLocation, publicType))
if (checkIsValidTypeAndQualifierForArray(arrayLocation, elementType))
{
TType arrayType = TType(publicType);
unsigned int size = checkIsValidArraySize(arrayLocation, indexExpression);
arrayType.makeArray(size);
TType arrayType(elementType);
arrayType.makeArray(arraySize);
if (IsAtomicCounter(publicType.getBasicType()))
checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &arrayType);
if (IsAtomicCounter(elementType.getBasicType()))
{
checkAtomicCounterOffsetIsNotOverlapped(publicType, kAtomicCounterArrayStride * size,
true, identifierLocation, arrayType);
checkAtomicCounterOffsetIsNotOverlapped(
elementType, kAtomicCounterArrayStride * arrayType.getArraySizeProduct(), true,
identifierLocation, arrayType);
}
TVariable *variable = nullptr;
......@@ -2667,7 +2645,8 @@ void TParseContext::parseInitDeclarator(const TPublicType &publicType,
checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
TIntermBinary *initNode = nullptr;
if (executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
TType type(publicType);
if (executeInitializer(identifierLocation, identifier, type, initializer, &initNode))
{
//
// build the intermediate representation
......@@ -2679,11 +2658,11 @@ void TParseContext::parseInitDeclarator(const TPublicType &publicType,
}
}
void TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
void TParseContext::parseArrayInitDeclarator(const TPublicType &elementType,
const TSourceLoc &identifierLocation,
const TString &identifier,
const TSourceLoc &indexLocation,
TIntermTyped *indexExpression,
unsigned int arraySize,
const TSourceLoc &initLocation,
TIntermTyped *initializer,
TIntermDeclaration *declarationOut)
......@@ -2692,26 +2671,16 @@ void TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
// not performed.
if (mDeferredNonEmptyDeclarationErrorCheck)
{
nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
nonEmptyDeclarationErrorCheck(elementType, identifierLocation);
mDeferredNonEmptyDeclarationErrorCheck = false;
}
checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
checkIsValidTypeAndQualifierForArray(indexLocation, publicType);
checkDeclaratorLocationIsNotSpecified(identifierLocation, elementType);
TPublicType arrayType(publicType);
checkIsValidTypeAndQualifierForArray(indexLocation, elementType);
unsigned int size = 0u;
// If indexExpression is nullptr, then the array will eventually get its size implicitly from
// the initializer.
if (indexExpression != nullptr)
{
size = checkIsValidArraySize(identifierLocation, indexExpression);
}
// Make the type an array even if size check failed.
// This ensures useless error messages regarding the variable's non-arrayness won't follow.
arrayType.setArraySize(size);
TType arrayType(elementType);
arrayType.makeArray(arraySize);
// initNode will correspond to the whole of "b[n] = initializer".
TIntermBinary *initNode = nullptr;
......@@ -3124,6 +3093,17 @@ TIntermFunctionPrototype *TParseContext::createPrototypeNodeFromFunction(
error(location, "redefinition", param.name->c_str());
}
}
// Unsized type of a named parameter should have already been checked and sanitized.
ASSERT(!param.type->isUnsizedArray());
}
else
{
if (param.type->isUnsizedArray())
{
error(location, "function parameter array must be sized at compile time", "[]");
// We don't need to size the arrays since the parameter is unnamed and hence
// inaccessible.
}
}
if (!symbol)
{
......@@ -3389,30 +3369,52 @@ TFunction *TParseContext::addConstructorFunc(const TPublicType &publicType)
return new TFunction(&symbolTable, nullptr, type, EOpConstruct);
}
TParameter TParseContext::parseParameterDeclarator(const TPublicType &publicType,
void TParseContext::checkIsNotUnsizedArray(const TSourceLoc &line,
const char *errorMessage,
const char *token,
TType *arrayType)
{
if (arrayType->isUnsizedArray())
{
error(line, errorMessage, token);
arrayType->sizeUnsizedArrays(TVector<unsigned int>());
}
}
TParameter TParseContext::parseParameterDeclarator(TType *type,
const TString *name,
const TSourceLoc &nameLoc)
{
if (publicType.getBasicType() == EbtVoid)
ASSERT(type);
checkIsNotUnsizedArray(nameLoc, "function parameter array must specify a size", name->c_str(),
type);
if (type->getBasicType() == EbtVoid)
{
error(nameLoc, "illegal use of type 'void'", name->c_str());
}
checkIsNotReserved(nameLoc, *name);
TType *type = new TType(publicType);
TParameter param = {name, type};
return param;
}
TParameter TParseContext::parseParameterArrayDeclarator(const TString *identifier,
const TSourceLoc &identifierLoc,
TIntermTyped *arraySize,
TParameter TParseContext::parseParameterDeclarator(const TPublicType &publicType,
const TString *name,
const TSourceLoc &nameLoc)
{
TType *type = new TType(publicType);
return parseParameterDeclarator(type, name, nameLoc);
}
TParameter TParseContext::parseParameterArrayDeclarator(const TString *name,
const TSourceLoc &nameLoc,
unsigned int arraySize,
const TSourceLoc &arrayLoc,
TPublicType *type)
TPublicType *elementType)
{
checkArrayElementIsNotArray(arrayLoc, *type);
unsigned int size = checkIsValidArraySize(arrayLoc, arraySize);
type->setArraySize(size);
return parseParameterDeclarator(*type, identifier, identifierLoc);
checkArrayElementIsNotArray(arrayLoc, *elementType);
TType *arrayType = new TType(*elementType);
arrayType->makeArray(arraySize);
return parseParameterDeclarator(arrayType, name, nameLoc);
}
bool TParseContext::checkUnsizedArrayConstructorArgumentDimensionality(TIntermSequence *arguments,
......@@ -4599,23 +4601,26 @@ TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecif
checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier);
for (unsigned int i = 0; i < declaratorList->size(); ++i)
for (TField *declarator : *declaratorList)
{
auto declaratorArraySizes = (*declaratorList)[i]->type()->getArraySizes();
auto declaratorArraySizes = declarator->type()->getArraySizes();
// don't allow arrays of arrays
if (!declaratorArraySizes.empty())
{
checkArrayElementIsNotArray(typeSpecifier.getLine(), typeSpecifier);
}
TType *type = (*declaratorList)[i]->type();
TType *type = declarator->type();
*type = TType(typeSpecifier);
for (unsigned int arraySize : declaratorArraySizes)
{
type->makeArray(arraySize);
}
checkIsNotUnsizedArray(typeSpecifier.getLine(),
"array members of structs must specify a size",
declarator->name().c_str(), type);
checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *(*declaratorList)[i]);
checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *declarator);
}
return declaratorList;
......
......@@ -148,7 +148,7 @@ class TParseContext : angle::NonCopyable
void nonEmptyDeclarationErrorCheck(const TPublicType &publicType,
const TSourceLoc &identifierLocation);
// Done only for empty declarations.
void emptyDeclarationErrorCheck(const TPublicType &publicType, const TSourceLoc &location);
void emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location);
void checkLayoutQualifierSupported(const TSourceLoc &location,
const TString &layoutQualifierName,
......@@ -180,7 +180,7 @@ class TParseContext : angle::NonCopyable
// is not needed in the AST.
bool executeInitializer(const TSourceLoc &line,
const TString &identifier,
const TPublicType &pType,
TType type,
TIntermTyped *initializer,
TIntermBinary **initNode);
TIntermNode *addConditionInitializer(const TPublicType &pType,
......@@ -205,11 +205,11 @@ class TParseContext : angle::NonCopyable
TIntermDeclaration *parseSingleDeclaration(TPublicType &publicType,
const TSourceLoc &identifierOrTypeLocation,
const TString &identifier);
TIntermDeclaration *parseSingleArrayDeclaration(TPublicType &publicType,
TIntermDeclaration *parseSingleArrayDeclaration(TPublicType &elementType,
const TSourceLoc &identifierLocation,
const TString &identifier,
const TSourceLoc &indexLocation,
TIntermTyped *indexExpression);
unsigned int arraySize);
TIntermDeclaration *parseSingleInitDeclaration(const TPublicType &publicType,
const TSourceLoc &identifierLocation,
const TString &identifier,
......@@ -218,11 +218,11 @@ class TParseContext : angle::NonCopyable
// Parse a declaration like "type a[n] = initializer"
// Note that this does not apply to declarations like "type[n] a = initializer"
TIntermDeclaration *parseSingleArrayInitDeclaration(TPublicType &publicType,
TIntermDeclaration *parseSingleArrayInitDeclaration(TPublicType &elementType,
const TSourceLoc &identifierLocation,
const TString &identifier,
const TSourceLoc &indexLocation,
TIntermTyped *indexExpression,
unsigned int arraySize,
const TSourceLoc &initLocation,
TIntermTyped *initializer);
......@@ -236,11 +236,11 @@ class TParseContext : angle::NonCopyable
const TSourceLoc &identifierLocation,
const TString &identifier,
TIntermDeclaration *declarationOut);
void parseArrayDeclarator(TPublicType &publicType,
void parseArrayDeclarator(TPublicType &elementType,
const TSourceLoc &identifierLocation,
const TString &identifier,
const TSourceLoc &arrayLocation,
TIntermTyped *indexExpression,
unsigned int arraySize,
TIntermDeclaration *declarationOut);
void parseInitDeclarator(const TPublicType &publicType,
const TSourceLoc &identifierLocation,
......@@ -250,11 +250,11 @@ class TParseContext : angle::NonCopyable
TIntermDeclaration *declarationOut);
// Parse a declarator like "a[n] = initializer"
void parseArrayInitDeclarator(const TPublicType &publicType,
void parseArrayInitDeclarator(const TPublicType &elementType,
const TSourceLoc &identifierLocation,
const TString &identifier,
const TSourceLoc &indexLocation,
TIntermTyped *indexExpression,
unsigned int arraySize,
const TSourceLoc &initLocation,
TIntermTyped *initializer,
TIntermDeclaration *declarationOut);
......@@ -281,11 +281,12 @@ class TParseContext : angle::NonCopyable
TParameter parseParameterDeclarator(const TPublicType &publicType,
const TString *name,
const TSourceLoc &nameLoc);
TParameter parseParameterArrayDeclarator(const TString *identifier,
const TSourceLoc &identifierLoc,
TIntermTyped *arraySize,
TParameter parseParameterArrayDeclarator(const TString *name,
const TSourceLoc &nameLoc,
unsigned int arraySize,
const TSourceLoc &arrayLoc,
TPublicType *type);
TPublicType *elementType);
TIntermTyped *addIndexExpression(TIntermTyped *baseExpression,
const TSourceLoc &location,
......@@ -453,7 +454,11 @@ class TParseContext : angle::NonCopyable
void checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
const TString &identifier,
TPublicType *type);
TType *type);
TParameter parseParameterDeclarator(TType *type,
const TString *name,
const TSourceLoc &nameLoc);
bool checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation,
const TPublicType &elementType);
......@@ -502,6 +507,13 @@ class TParseContext : angle::NonCopyable
TType type,
const TSourceLoc &line);
// Will size any unsized array type so unsized arrays won't need to be taken into account
// further along the line in parsing.
void checkIsNotUnsizedArray(const TSourceLoc &line,
const char *errorMessage,
const char *token,
TType *arrayType);
TIntermTyped *addBinaryMathInternal(TOperator op,
TIntermTyped *left,
TIntermTyped *right,
......
......@@ -577,6 +577,12 @@ void TType::sizeUnsizedArrays(const TVector<unsigned int> &arraySizes)
invalidateMangledName();
}
void TType::sizeOutermostUnsizedArray(unsigned int arraySize)
{
ASSERT(isArray());
mArraySizes.back() = arraySize;
}
TStructure::TStructure(TSymbolTable *symbolTable, const TString *name, TFieldList *fields)
: TFieldListCollection(name, fields),
mDeepestNesting(0),
......
......@@ -349,6 +349,9 @@ class TType
// than there are sizes in arraySizes, defaults to setting array sizes to 1.
void sizeUnsizedArrays(const TVector<unsigned int> &arraySizes);
// Will size the outermost array according to arraySize.
void sizeOutermostUnsizedArray(unsigned int arraySize);
// Note that the array element type might still be an array type in GLSL ES version >= 3.10.
void toArrayElementType()
{
......@@ -636,7 +639,6 @@ struct TPublicType
return typeSpecifierNonArray.userDef->containsType(t);
}
bool isUnsizedArray() const { return array && arraySize == 0; }
void setArraySize(int s)
{
array = true;
......
......@@ -86,6 +86,7 @@ using namespace sh;
TIntermCase *intermCase;
};
union {
unsigned int arraySize;
TTypeSpecifierNonArray typeSpecifierNonArray;
TPublicType type;
TPrecision precision;
......@@ -218,6 +219,8 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons
%type <interm.param> parameter_declaration parameter_declarator parameter_type_specifier
%type <interm.layoutQualifier> layout_qualifier_id_list layout_qualifier_id
%type <interm.arraySize> array_specifier
%type <interm.type> fully_specified_type type_specifier
%type <interm.precision> precision_qualifier
......@@ -681,8 +684,8 @@ parameter_declarator
: type_specifier identifier {
$$ = context->parseParameterDeclarator($1, $2.string, @2);
}
| type_specifier identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
$$ = context->parseParameterArrayDeclarator($2.string, @2, $4, @3, &$1);
| type_specifier identifier array_specifier {
$$ = context->parseParameterArrayDeclarator($2.string, @2, $3, @3, &$1);
}
;
......@@ -720,19 +723,14 @@ init_declarator_list
$$ = $1;
context->parseDeclarator($$.type, @3, *$3.string, $$.intermDeclaration);
}
| init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
$$ = $1;
context->parseArrayDeclarator($$.type, @3, *$3.string, @4, $5, $$.intermDeclaration);
}
| init_declarator_list COMMA identifier LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {
ES3_OR_NEWER("[]", @3, "implicitly sized array");
| init_declarator_list COMMA identifier array_specifier {
$$ = $1;
context->parseArrayInitDeclarator($$.type, @3, *$3.string, @4, nullptr, @6, $7, $$.intermDeclaration);
context->parseArrayDeclarator($$.type, @3, *$3.string, @4, $4, $$.intermDeclaration);
}
| init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {
ES3_OR_NEWER("=", @7, "first-class arrays (array initializer)");
| init_declarator_list COMMA identifier array_specifier EQUAL initializer {
ES3_OR_NEWER("=", @5, "first-class arrays (array initializer)");
$$ = $1;
context->parseArrayInitDeclarator($$.type, @3, *$3.string, @4, $5, @7, $8, $$.intermDeclaration);
context->parseArrayInitDeclarator($$.type, @3, *$3.string, @4, $4, @5, $6, $$.intermDeclaration);
}
| init_declarator_list COMMA identifier EQUAL initializer {
$$ = $1;
......@@ -749,24 +747,14 @@ single_declaration
$$.type = $1;
$$.intermDeclaration = context->parseSingleDeclaration($$.type, @2, *$2.string);
}
| fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET {
ES3_1_ONLY("[]", @3, "implicitly sized array declaration");
| fully_specified_type identifier array_specifier {
$$.type = $1;
$$.intermDeclaration = context->parseSingleArrayDeclaration($$.type, @2, *$2.string, @3, nullptr);
$$.intermDeclaration = context->parseSingleArrayDeclaration($$.type, @2, *$2.string, @3, $3);
}
| fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
| fully_specified_type identifier array_specifier EQUAL initializer {
ES3_OR_NEWER("[]", @3, "first-class arrays (array initializer)");
$$.type = $1;
$$.intermDeclaration = context->parseSingleArrayDeclaration($$.type, @2, *$2.string, @3, $4);
}
| fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {
ES3_OR_NEWER("[]", @3, "implicitly sized array");
$$.type = $1;
$$.intermDeclaration = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, nullptr, @5, $6);
}
| fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {
ES3_OR_NEWER("=", @6, "first-class arrays (array initializer)");
$$.type = $1;
$$.intermDeclaration = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, $4, @6, $7);
$$.intermDeclaration = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, $3, @4, $5);
}
| fully_specified_type identifier EQUAL initializer {
$$.type = $1;
......@@ -941,15 +929,22 @@ type_specifier_no_prec
: type_specifier_nonarray {
$$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
}
| type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET {
ES3_OR_NEWER("[]", @2, "implicitly sized array");
| type_specifier_nonarray array_specifier {
$$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
$$.setArraySize(0);
$$.setArraySize($2);
}
| type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
$$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
unsigned int size = context->checkIsValidArraySize(@2, $3);
$$.setArraySize(size);
;
array_specifier
: LEFT_BRACKET RIGHT_BRACKET {
ES3_OR_NEWER("[]", @1, "implicitly sized array");
$$ = 0u;
}
| LEFT_BRACKET constant_expression RIGHT_BRACKET {
unsigned int size = context->checkIsValidArraySize(@1, $2);
// Make the type an array even if size check failed.
// This ensures useless error messages regarding a variable's non-arrayness won't follow.
$$ = size;
}
;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -238,6 +238,7 @@ union YYSTYPE
TIntermCase *intermCase;
};
union {
unsigned int arraySize;
TTypeSpecifierNonArray typeSpecifierNonArray;
TPublicType type;
TPrecision precision;
......
......@@ -5104,3 +5104,51 @@ TEST_F(FragmentShaderValidationTest, UnsizedInputs)
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that unsized struct members are not allowed.
TEST_F(FragmentShaderValidationTest, UnsizedStructMember)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
out vec4 color;
struct S
{
int[] foo;
};
void main()
{
color = vec4(1.0);
})";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that unsized parameters without a name are not allowed.
// GLSL ES 3.10 section 6.1 Function Definitions.
TEST_F(FragmentShaderValidationTest, UnsizedNamelessParameter)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
out vec4 color;
void foo(int[]);
void main()
{
color = vec4(1.0);
})";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment