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
...@@ -148,7 +148,7 @@ class TParseContext : angle::NonCopyable ...@@ -148,7 +148,7 @@ class TParseContext : angle::NonCopyable
void nonEmptyDeclarationErrorCheck(const TPublicType &publicType, void nonEmptyDeclarationErrorCheck(const TPublicType &publicType,
const TSourceLoc &identifierLocation); const TSourceLoc &identifierLocation);
// Done only for empty declarations. // 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, void checkLayoutQualifierSupported(const TSourceLoc &location,
const TString &layoutQualifierName, const TString &layoutQualifierName,
...@@ -180,7 +180,7 @@ class TParseContext : angle::NonCopyable ...@@ -180,7 +180,7 @@ class TParseContext : angle::NonCopyable
// is not needed in the AST. // is not needed in the AST.
bool executeInitializer(const TSourceLoc &line, bool executeInitializer(const TSourceLoc &line,
const TString &identifier, const TString &identifier,
const TPublicType &pType, TType type,
TIntermTyped *initializer, TIntermTyped *initializer,
TIntermBinary **initNode); TIntermBinary **initNode);
TIntermNode *addConditionInitializer(const TPublicType &pType, TIntermNode *addConditionInitializer(const TPublicType &pType,
...@@ -205,11 +205,11 @@ class TParseContext : angle::NonCopyable ...@@ -205,11 +205,11 @@ class TParseContext : angle::NonCopyable
TIntermDeclaration *parseSingleDeclaration(TPublicType &publicType, TIntermDeclaration *parseSingleDeclaration(TPublicType &publicType,
const TSourceLoc &identifierOrTypeLocation, const TSourceLoc &identifierOrTypeLocation,
const TString &identifier); const TString &identifier);
TIntermDeclaration *parseSingleArrayDeclaration(TPublicType &publicType, TIntermDeclaration *parseSingleArrayDeclaration(TPublicType &elementType,
const TSourceLoc &identifierLocation, const TSourceLoc &identifierLocation,
const TString &identifier, const TString &identifier,
const TSourceLoc &indexLocation, const TSourceLoc &indexLocation,
TIntermTyped *indexExpression); unsigned int arraySize);
TIntermDeclaration *parseSingleInitDeclaration(const TPublicType &publicType, TIntermDeclaration *parseSingleInitDeclaration(const TPublicType &publicType,
const TSourceLoc &identifierLocation, const TSourceLoc &identifierLocation,
const TString &identifier, const TString &identifier,
...@@ -218,11 +218,11 @@ class TParseContext : angle::NonCopyable ...@@ -218,11 +218,11 @@ class TParseContext : angle::NonCopyable
// Parse a declaration like "type a[n] = initializer" // Parse a declaration like "type a[n] = initializer"
// Note that this does not apply to declarations like "type[n] a = 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 TSourceLoc &identifierLocation,
const TString &identifier, const TString &identifier,
const TSourceLoc &indexLocation, const TSourceLoc &indexLocation,
TIntermTyped *indexExpression, unsigned int arraySize,
const TSourceLoc &initLocation, const TSourceLoc &initLocation,
TIntermTyped *initializer); TIntermTyped *initializer);
...@@ -236,11 +236,11 @@ class TParseContext : angle::NonCopyable ...@@ -236,11 +236,11 @@ class TParseContext : angle::NonCopyable
const TSourceLoc &identifierLocation, const TSourceLoc &identifierLocation,
const TString &identifier, const TString &identifier,
TIntermDeclaration *declarationOut); TIntermDeclaration *declarationOut);
void parseArrayDeclarator(TPublicType &publicType, void parseArrayDeclarator(TPublicType &elementType,
const TSourceLoc &identifierLocation, const TSourceLoc &identifierLocation,
const TString &identifier, const TString &identifier,
const TSourceLoc &arrayLocation, const TSourceLoc &arrayLocation,
TIntermTyped *indexExpression, unsigned int arraySize,
TIntermDeclaration *declarationOut); TIntermDeclaration *declarationOut);
void parseInitDeclarator(const TPublicType &publicType, void parseInitDeclarator(const TPublicType &publicType,
const TSourceLoc &identifierLocation, const TSourceLoc &identifierLocation,
...@@ -250,11 +250,11 @@ class TParseContext : angle::NonCopyable ...@@ -250,11 +250,11 @@ class TParseContext : angle::NonCopyable
TIntermDeclaration *declarationOut); TIntermDeclaration *declarationOut);
// Parse a declarator like "a[n] = initializer" // Parse a declarator like "a[n] = initializer"
void parseArrayInitDeclarator(const TPublicType &publicType, void parseArrayInitDeclarator(const TPublicType &elementType,
const TSourceLoc &identifierLocation, const TSourceLoc &identifierLocation,
const TString &identifier, const TString &identifier,
const TSourceLoc &indexLocation, const TSourceLoc &indexLocation,
TIntermTyped *indexExpression, unsigned int arraySize,
const TSourceLoc &initLocation, const TSourceLoc &initLocation,
TIntermTyped *initializer, TIntermTyped *initializer,
TIntermDeclaration *declarationOut); TIntermDeclaration *declarationOut);
...@@ -281,11 +281,12 @@ class TParseContext : angle::NonCopyable ...@@ -281,11 +281,12 @@ class TParseContext : angle::NonCopyable
TParameter parseParameterDeclarator(const TPublicType &publicType, TParameter parseParameterDeclarator(const TPublicType &publicType,
const TString *name, const TString *name,
const TSourceLoc &nameLoc); const TSourceLoc &nameLoc);
TParameter parseParameterArrayDeclarator(const TString *identifier,
const TSourceLoc &identifierLoc, TParameter parseParameterArrayDeclarator(const TString *name,
TIntermTyped *arraySize, const TSourceLoc &nameLoc,
unsigned int arraySize,
const TSourceLoc &arrayLoc, const TSourceLoc &arrayLoc,
TPublicType *type); TPublicType *elementType);
TIntermTyped *addIndexExpression(TIntermTyped *baseExpression, TIntermTyped *addIndexExpression(TIntermTyped *baseExpression,
const TSourceLoc &location, const TSourceLoc &location,
...@@ -453,7 +454,11 @@ class TParseContext : angle::NonCopyable ...@@ -453,7 +454,11 @@ class TParseContext : angle::NonCopyable
void checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line, void checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
const TString &identifier, const TString &identifier,
TPublicType *type); TType *type);
TParameter parseParameterDeclarator(TType *type,
const TString *name,
const TSourceLoc &nameLoc);
bool checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation, bool checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation,
const TPublicType &elementType); const TPublicType &elementType);
...@@ -502,6 +507,13 @@ class TParseContext : angle::NonCopyable ...@@ -502,6 +507,13 @@ class TParseContext : angle::NonCopyable
TType type, TType type,
const TSourceLoc &line); 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 *addBinaryMathInternal(TOperator op,
TIntermTyped *left, TIntermTyped *left,
TIntermTyped *right, TIntermTyped *right,
......
...@@ -577,6 +577,12 @@ void TType::sizeUnsizedArrays(const TVector<unsigned int> &arraySizes) ...@@ -577,6 +577,12 @@ void TType::sizeUnsizedArrays(const TVector<unsigned int> &arraySizes)
invalidateMangledName(); invalidateMangledName();
} }
void TType::sizeOutermostUnsizedArray(unsigned int arraySize)
{
ASSERT(isArray());
mArraySizes.back() = arraySize;
}
TStructure::TStructure(TSymbolTable *symbolTable, const TString *name, TFieldList *fields) TStructure::TStructure(TSymbolTable *symbolTable, const TString *name, TFieldList *fields)
: TFieldListCollection(name, fields), : TFieldListCollection(name, fields),
mDeepestNesting(0), mDeepestNesting(0),
......
...@@ -349,6 +349,9 @@ class TType ...@@ -349,6 +349,9 @@ class TType
// than there are sizes in arraySizes, defaults to setting array sizes to 1. // than there are sizes in arraySizes, defaults to setting array sizes to 1.
void sizeUnsizedArrays(const TVector<unsigned int> &arraySizes); 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. // Note that the array element type might still be an array type in GLSL ES version >= 3.10.
void toArrayElementType() void toArrayElementType()
{ {
...@@ -636,7 +639,6 @@ struct TPublicType ...@@ -636,7 +639,6 @@ struct TPublicType
return typeSpecifierNonArray.userDef->containsType(t); return typeSpecifierNonArray.userDef->containsType(t);
} }
bool isUnsizedArray() const { return array && arraySize == 0; }
void setArraySize(int s) void setArraySize(int s)
{ {
array = true; array = true;
......
...@@ -86,6 +86,7 @@ using namespace sh; ...@@ -86,6 +86,7 @@ using namespace sh;
TIntermCase *intermCase; TIntermCase *intermCase;
}; };
union { union {
unsigned int arraySize;
TTypeSpecifierNonArray typeSpecifierNonArray; TTypeSpecifierNonArray typeSpecifierNonArray;
TPublicType type; TPublicType type;
TPrecision precision; TPrecision precision;
...@@ -218,6 +219,8 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons ...@@ -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.param> parameter_declaration parameter_declarator parameter_type_specifier
%type <interm.layoutQualifier> layout_qualifier_id_list layout_qualifier_id %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.type> fully_specified_type type_specifier
%type <interm.precision> precision_qualifier %type <interm.precision> precision_qualifier
...@@ -681,8 +684,8 @@ parameter_declarator ...@@ -681,8 +684,8 @@ parameter_declarator
: type_specifier identifier { : type_specifier identifier {
$$ = context->parseParameterDeclarator($1, $2.string, @2); $$ = context->parseParameterDeclarator($1, $2.string, @2);
} }
| type_specifier identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { | type_specifier identifier array_specifier {
$$ = context->parseParameterArrayDeclarator($2.string, @2, $4, @3, &$1); $$ = context->parseParameterArrayDeclarator($2.string, @2, $3, @3, &$1);
} }
; ;
...@@ -720,19 +723,14 @@ init_declarator_list ...@@ -720,19 +723,14 @@ init_declarator_list
$$ = $1; $$ = $1;
context->parseDeclarator($$.type, @3, *$3.string, $$.intermDeclaration); context->parseDeclarator($$.type, @3, *$3.string, $$.intermDeclaration);
} }
| init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { | init_declarator_list COMMA identifier array_specifier {
$$ = $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");
$$ = $1; $$ = $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 { | init_declarator_list COMMA identifier array_specifier EQUAL initializer {
ES3_OR_NEWER("=", @7, "first-class arrays (array initializer)"); ES3_OR_NEWER("=", @5, "first-class arrays (array initializer)");
$$ = $1; $$ = $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 { | init_declarator_list COMMA identifier EQUAL initializer {
$$ = $1; $$ = $1;
...@@ -749,24 +747,14 @@ single_declaration ...@@ -749,24 +747,14 @@ single_declaration
$$.type = $1; $$.type = $1;
$$.intermDeclaration = context->parseSingleDeclaration($$.type, @2, *$2.string); $$.intermDeclaration = context->parseSingleDeclaration($$.type, @2, *$2.string);
} }
| fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET { | fully_specified_type identifier array_specifier {
ES3_1_ONLY("[]", @3, "implicitly sized array declaration");
$$.type = $1; $$.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; $$.type = $1;
$$.intermDeclaration = context->parseSingleArrayDeclaration($$.type, @2, *$2.string, @3, $4); $$.intermDeclaration = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, $3, @4, $5);
}
| 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);
} }
| fully_specified_type identifier EQUAL initializer { | fully_specified_type identifier EQUAL initializer {
$$.type = $1; $$.type = $1;
...@@ -941,15 +929,22 @@ type_specifier_no_prec ...@@ -941,15 +929,22 @@ type_specifier_no_prec
: type_specifier_nonarray { : type_specifier_nonarray {
$$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary)); $$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
} }
| type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET { | type_specifier_nonarray array_specifier {
ES3_OR_NEWER("[]", @2, "implicitly sized array");
$$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary)); $$.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); array_specifier
$$.setArraySize(size); : 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 ...@@ -238,6 +238,7 @@ union YYSTYPE
TIntermCase *intermCase; TIntermCase *intermCase;
}; };
union { union {
unsigned int arraySize;
TTypeSpecifierNonArray typeSpecifierNonArray; TTypeSpecifierNonArray typeSpecifierNonArray;
TPublicType type; TPublicType type;
TPrecision precision; TPrecision precision;
......
...@@ -5104,3 +5104,51 @@ TEST_F(FragmentShaderValidationTest, UnsizedInputs) ...@@ -5104,3 +5104,51 @@ TEST_F(FragmentShaderValidationTest, UnsizedInputs)
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; 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