Commit 376f1b5d by Olli Etuaho

Add support for implicit array size

ESSL3 introduces implicit array size that is determined automatically according to the initializer. Implicit sizes are resolved when parsing constructors and when initializers are evaluated, so ANGLE's AST will not contain implicit sizes. Declarations where there are two differently sized arrays with the same implicitly sized type, for example: float[] a = float[](0.0), b = float[](0.0, 1.0); will be transformed into declarations where the two arrays don't share the array size like this: float a[1] = float[1](0.0), float b[2] = float[2](0.0, 1.0); so they are not a problem. Unlike sized arrays, implicitly sized arrays don't have a size limit enforced by the parser. Include a test that verifies that non-initialization of an implicitly sized array defined using ESSL3 type syntax is caught by the parser. Additionally tested with WebGL 2 test sdk/tests/deqp/data/gles3/shaders/arrays.html TEST=WebGL 2 conformance tests, angle_unittests BUG=angleproject:941 Change-Id: Ib55b7601848102a103af9db284a80f09abaeb021 Reviewed-on: https://chromium-review.googlesource.com/265653Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent 3875ffd1
......@@ -512,9 +512,17 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc& line, TIntermNode* n
if (constType)
type->setQualifier(EvqConst);
if (type->isArray() && static_cast<size_t>(type->getArraySize()) != function.getParamCount()) {
error(line, "array constructor needs one argument per array element", "constructor");
return true;
if (type->isArray())
{
if (type->isUnsizedArray())
{
type->setArraySize(function.getParamCount());
}
else if (static_cast<size_t>(type->getArraySize()) != function.getParamCount())
{
error(line, "array constructor needs one argument per array element", "constructor");
return true;
}
}
if (arrayArg && op != EOpConstructStruct) {
......@@ -763,7 +771,7 @@ bool TParseContext::arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type
//
// Returns true if there was an error.
//
bool TParseContext::nonInitConstErrorCheck(const TSourceLoc &line, const TString &identifier, TPublicType *type)
bool TParseContext::nonInitErrorCheck(const TSourceLoc &line, const TString &identifier, TPublicType *type)
{
ASSERT(type != nullptr);
if (type->qualifier == EvqConst)
......@@ -784,6 +792,11 @@ bool TParseContext::nonInitConstErrorCheck(const TSourceLoc &line, const TString
return true;
}
if (type->isUnsizedArray())
{
error(line, "implicitly sized arrays need to be initialized", identifier.c_str());
return true;
}
return false;
}
......@@ -1083,6 +1096,10 @@ bool TParseContext::executeInitializer(const TSourceLoc &line, const TString &id
TType type = TType(pType);
TVariable *variable = nullptr;
if (type.isUnsizedArray())
{
type.setArraySize(initializer->getArraySize());
}
if (!declareVariable(line, identifier, type, &variable))
{
return true;
......@@ -1252,7 +1269,7 @@ TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType,
if (singleDeclarationErrorCheck(publicType, identifierOrTypeLocation))
recover();
if (nonInitConstErrorCheck(identifierOrTypeLocation, identifier, &publicType))
if (nonInitErrorCheck(identifierOrTypeLocation, identifier, &publicType))
recover();
TVariable *variable = nullptr;
......@@ -1277,7 +1294,7 @@ TIntermAggregate *TParseContext::parseSingleArrayDeclaration(TPublicType &public
if (singleDeclarationErrorCheck(publicType, identifierLocation))
recover();
if (nonInitConstErrorCheck(identifierLocation, identifier, &publicType))
if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
recover();
if (arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType))
......@@ -1353,8 +1370,9 @@ TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration(TPublicType &pu
TPublicType arrayType(publicType);
int size;
if (arraySizeErrorCheck(identifierLocation, indexExpression, size))
int size = 0;
// If indexExpression is nullptr, then the array will eventually get its size implicitly from the initializer.
if (indexExpression != nullptr && arraySizeErrorCheck(identifierLocation, indexExpression, size))
{
recover();
}
......@@ -1428,7 +1446,7 @@ TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType, TInter
if (locationDeclaratorListCheck(identifierLocation, publicType))
recover();
if (nonInitConstErrorCheck(identifierLocation, identifier, &publicType))
if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
recover();
TVariable *variable = nullptr;
......@@ -1457,7 +1475,7 @@ TIntermAggregate *TParseContext::parseArrayDeclarator(TPublicType &publicType, T
if (locationDeclaratorListCheck(identifierLocation, publicType))
recover();
if (nonInitConstErrorCheck(identifierLocation, identifier, &publicType))
if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
recover();
if (arrayTypeErrorCheck(arrayLocation, publicType) || arrayQualifierErrorCheck(arrayLocation, publicType))
......@@ -1551,8 +1569,9 @@ TIntermAggregate *TParseContext::parseArrayInitDeclarator(TPublicType &publicTyp
TPublicType arrayType(publicType);
int size;
if (arraySizeErrorCheck(identifierLocation, indexExpression, size))
int size = 0;
// If indexExpression is nullptr, then the array will eventually get its size implicitly from the initializer.
if (indexExpression != nullptr && arraySizeErrorCheck(identifierLocation, indexExpression, size))
{
recover();
}
......@@ -2873,6 +2892,7 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TInter
error(loc, "Invalid operation for arrays", GetOperatorString(op));
return false;
}
// At this point, size of implicitly sized arrays should be resolved.
if (left->getArraySize() != right->getArraySize())
{
error(loc, "array size mismatch", GetOperatorString(op));
......
......@@ -106,7 +106,6 @@ struct TParseContext {
bool samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason);
bool locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType);
bool parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type);
bool nonInitConstErrorCheck(const TSourceLoc &line, const TString &identifier, TPublicType *type);
bool paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type);
bool extensionErrorCheck(const TSourceLoc& line, const TString&);
bool singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc &identifierLocation);
......@@ -216,6 +215,8 @@ struct TParseContext {
private:
bool declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, TVariable **variable);
bool nonInitErrorCheck(const TSourceLoc &line, const TString &identifier, TPublicType *type);
TIntermTyped *addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right,
const TSourceLoc &loc);
TIntermTyped *createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right,
......
......@@ -340,7 +340,11 @@ class TType
}
bool isArray() const
{
return array ? true : false;
return array;
}
bool isUnsizedArray() const
{
return array && arraySize == 0;
}
int getArraySize() const
{
......@@ -553,6 +557,10 @@ struct TPublicType
secondarySize = r;
}
bool isUnsizedArray() const
{
return array && arraySize == 0;
}
void setArraySize(int s)
{
array = true;
......
......@@ -889,6 +889,11 @@ init_declarator_list
$$ = $1;
$$.intermAggregate = context->parseArrayDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5);
}
| init_declarator_list COMMA identifier LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {
ES3_ONLY("[]", @3, "implicitly sized array");
$$ = $1;
$$.intermAggregate = context->parseArrayInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, nullptr, @6, $7);
}
| init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {
ES3_ONLY("=", @7, "first-class arrays (array initializer)");
$$ = $1;
......@@ -909,17 +914,15 @@ single_declaration
$$.type = $1;
$$.intermAggregate = context->parseSingleDeclaration($$.type, @2, *$2.string);
}
| fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET {
context->error(@2, "unsized array declarations not supported", $2.string->c_str());
context->recover();
$$.type = $1;
$$.intermAggregate = context->parseSingleDeclaration($$.type, @2, *$2.string);
}
| fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
$$.type = $1;
$$.intermAggregate = context->parseSingleArrayDeclaration($$.type, @2, *$2.string, @3, $4);
}
| fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {
ES3_ONLY("[]", @3, "implicitly sized array");
$$.type = $1;
$$.intermAggregate = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, nullptr, @5, $6);
}
| fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {
ES3_ONLY("=", @6, "first-class arrays (array initializer)");
$$.type = $1;
......@@ -1123,6 +1126,11 @@ type_specifier_no_prec
: type_specifier_nonarray {
$$ = $1;
}
| type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET {
ES3_ONLY("[]", @2, "implicitly sized array");
$$ = $1;
$$.setArraySize(0);
}
| type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
$$ = $1;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -347,3 +347,20 @@ TEST_F(MalformedShaderTest, ArraysOfArrays2)
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Implicitly sized arrays need to be initialized (ESSL 3.00 section 4.1.9)
TEST_F(MalformedShaderTest, UninitializedImplicitArraySize)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" float[] a;\n"
" my_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << 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