HLSL: phase 2c: use lValueErrorCheck in HLSL FE

This commit splits lValueErrorCheck into machine dependent and independent
parts.  The GLSL form in TParseContext inherits from and invokes the
machine dependent part in TParseContextBase.  The base form checks language
independent things.  This split does not change the set of errors tested
for: the test results are identical.

The new base class interface is now used from the HLSL FE to test lvalues.
There was one test diff due to this, where the test was writing to a uniform.
It still does the same indirections, but does not attempt a uniform write.
This commit is contained in:
steve-lunarg 2016-10-08 10:54:52 -06:00
parent 90707966ea
commit 0de16da2c0
7 changed files with 222 additions and 130 deletions

View file

@ -1902,14 +1902,14 @@ void TParseContext::variableCheck(TIntermTyped*& nodePtr)
// Both test and if necessary, spit out an error, to see if the node is really
// an l-value that can be operated on this way.
//
// Returns true if the was an error.
// Returns true if there was an error.
//
bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
{
TIntermBinary* binaryNode = node->getAsBinaryNode();
if (binaryNode) {
bool errorReturn;
bool errorReturn = false;
switch(binaryNode->getOp()) {
case EOpIndexDirect:
@ -1928,9 +1928,9 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
}
}
// fall through
break; // left node is checked by base class
case EOpIndexDirectStruct:
return lValueErrorCheck(loc, op, binaryNode->getLeft());
break; // left node is checked by base class
case EOpVectorSwizzle:
errorReturn = lValueErrorCheck(loc, op, binaryNode->getLeft());
if (!errorReturn) {
@ -1955,12 +1955,18 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
default:
break;
}
error(loc, " l-value required", op, "", "");
return true;
if (errorReturn) {
error(loc, " l-value required", op, "", "");
return true;
}
}
// Let the base class check errors
if (TParseContextBase::lValueErrorCheck(loc, op, node))
return true;
// GLSL specific
const char* symbol = nullptr;
TIntermSymbol* symNode = node->getAsSymbolNode();
if (symNode != nullptr)
@ -1968,19 +1974,12 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
const char* message = nullptr;
switch (node->getQualifier().storage) {
case EvqConst: message = "can't modify a const"; break;
case EvqConstReadOnly: message = "can't modify a const"; break;
case EvqVaryingIn: message = "can't modify shader input"; break;
case EvqInstanceId: message = "can't modify gl_InstanceID"; break;
case EvqVertexId: message = "can't modify gl_VertexID"; break;
case EvqFace: message = "can't modify gl_FrontFace"; break;
case EvqFragCoord: message = "can't modify gl_FragCoord"; break;
case EvqPointCoord: message = "can't modify gl_PointCoord"; break;
case EvqUniform: message = "can't modify a uniform"; break;
case EvqBuffer:
if (node->getQualifier().readonly)
message = "can't modify a readonly buffer";
break;
case EvqFragDepth:
intermediate.setDepthReplacing();
// "In addition, it is an error to statically write to gl_FragDepth in the fragment shader."
@ -1989,22 +1988,7 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
break;
default:
//
// Type that can't be written to?
//
switch (node->getBasicType()) {
case EbtSampler:
message = "can't modify a sampler";
break;
case EbtAtomicUint:
message = "can't modify an atomic_uint";
break;
case EbtVoid:
message = "can't modify void";
break;
default:
break;
}
break;
}
if (message == nullptr && binaryNode == nullptr && symNode == nullptr) {
@ -2013,7 +1997,6 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
return true;
}
//
// Everything else is okay, no error.
//
@ -2034,30 +2017,14 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
// Test for and give an error if the node can't be read from.
void TParseContext::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
{
if (! node)
return;
// Let the base class check errors
TParseContextBase::rValueErrorCheck(loc, op, node);
TIntermBinary* binaryNode = node->getAsBinaryNode();
if (binaryNode) {
switch(binaryNode->getOp()) {
case EOpIndexDirect:
case EOpIndexIndirect:
case EOpIndexDirectStruct:
case EOpVectorSwizzle:
rValueErrorCheck(loc, op, binaryNode->getLeft());
default:
break;
}
return;
}
TIntermSymbol* symNode = node->getAsSymbolNode();
if (symNode && symNode->getQualifier().writeonly)
error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str());
#ifdef AMD_EXTENSIONS
else if (symNode && symNode->getQualifier().explicitInterp)
error(loc, "can't read from explicitly-interpolated object: ", op, symNode->getName().c_str());
TIntermSymbol* symNode = node->getAsSymbolNode();
if (!(symNode && symNode->getQualifier().writeonly)) // base class checks
if (symNode && symNode->getQualifier().explicitInterp)
error(loc, "can't read from explicitly-interpolated object: ", op, symNode->getName().c_str());
#endif
}