Improve robustness for symbol downcasts by moving to a "getAs" infrastructure and doing more error checking.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@20609 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2013-02-14 19:02:23 +00:00
parent e25cd0447d
commit fb5f7eadfa
5 changed files with 104 additions and 77 deletions

View File

@ -70,7 +70,7 @@ void TParseContext::setVersion(int newVersion)
defaultPrecision[EbtFloat] = EpqHigh;
defaultPrecision[EbtSampler2D] = EpqLow;
defaultPrecision[EbtSamplerCube] = EpqLow;
}
}
if (language == EShLangFragment) {
defaultPrecision[EbtInt] = EpqMedium;
@ -728,7 +728,6 @@ bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType
void TParseContext::setDefaultPrecision(int line, TBasicType type, TPrecisionQualifier qualifier)
{
// TODO: push and pop for nested scopes
if (IsSampler(type) || type == EbtInt || type == EbtFloat) {
defaultPrecision[type] = qualifier;
} else {
@ -772,7 +771,12 @@ bool TParseContext::insertBuiltInArrayAtGlobalLevel()
error(0, "INTERNAL ERROR finding symbol", name->c_str(), "");
return true;
}
TVariable* variable = static_cast<TVariable*>(symbol);
TVariable* variable = symbol->getAsVariable();
if (! variable) {
error(0, "INTERNAL ERROR, variable expected", name->c_str(), "");
return true;
}
TVariable* newVariable = new TVariable(name, variable->getType());
@ -785,8 +789,6 @@ bool TParseContext::insertBuiltInArrayAtGlobalLevel()
return false;
}
//
// Do size checking for an array type's size.
//
@ -877,12 +879,13 @@ bool TParseContext::arrayErrorCheck(int line, TString& identifier, TPublicType t
return true;
}
} else {
if (! symbol->isVariable()) {
error(line, "variable expected", identifier.c_str(), "");
variable = symbol->getAsVariable();
if (! variable) {
error(line, "array variable name expected", identifier.c_str(), "");
return true;
}
variable = static_cast<TVariable*>(symbol);
if (! variable->getType().isArray()) {
error(line, "redeclaring non-array as array", identifier.c_str(), "");
return true;
@ -924,7 +927,12 @@ bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size,
error(line, " undeclared identifier", node->getSymbol().c_str(), "");
return true;
}
TVariable* variable = static_cast<TVariable*>(symbol);
TVariable* variable = symbol->getAsVariable();
if (! variable) {
error(0, "array variable name expected", node->getSymbol().c_str(), "");
return true;
}
type->setArrayInformationType(variable->getArrayInformationType());
variable->updateArrayInformationType(type);
@ -933,12 +941,12 @@ bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size,
// its an error
if (node->getSymbol() == "gl_TexCoord") {
TSymbol* texCoord = symbolTable.find("gl_MaxTextureCoords", &builtIn);
if (texCoord == 0) {
if (! texCoord || ! texCoord->getAsVariable()) {
infoSink.info.message(EPrefixInternalError, "gl_MaxTextureCoords not defined", line);
return true;
}
int texCoordValue = static_cast<TVariable*>(texCoord)->getConstPointer()[0].getIConst();
int texCoordValue = texCoord->getAsVariable()->getConstUnionPointer()[0].getIConst();
if (texCoordValue <= size) {
error(line, "", "[", "gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords", "");
return true;
@ -1042,19 +1050,20 @@ bool TParseContext::paramErrorCheck(int line, TStorageQualifier qualifier, TType
//
const TFunction* TParseContext::findFunction(int line, TFunction* call, bool *builtIn)
{
const TSymbol* symbol = symbolTable.find(call->getMangledName(), builtIn);
TSymbol* symbol = symbolTable.find(call->getMangledName(), builtIn);
if (symbol == 0) {
error(line, "no matching overloaded function found", call->getName().c_str(), "");
return 0;
}
if (! symbol->isFunction()) {
error(line, "function name expected", call->getName().c_str(), "");
return 0;
}
const TFunction* function = static_cast<const TFunction*>(symbol);
const TFunction* function = symbol->getAsFunction();
if (! function) {
error(line, "function name expected", call->getName().c_str(), "");
return 0;
}
return function;
}
@ -1117,7 +1126,7 @@ bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPu
return true;
}
if (initializer->getAsConstantUnion()) {
constUnion* unionArray = variable->getConstPointer();
constUnion* unionArray = variable->getConstUnionPointer();
if (type.getObjectSize() == 1 && type.getBasicType() != EbtStruct) {
*unionArray = (initializer->getAsConstantUnion()->getUnionArrayPointer())[0];
@ -1125,11 +1134,14 @@ bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPu
variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
}
} else if (initializer->getAsSymbolNode()) {
const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol());
const TVariable* tVar = static_cast<const TVariable*>(symbol);
constUnion* constArray = tVar->getConstPointer();
variable->shareConstPointer(constArray);
TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol());
if (TVariable* tVar = symbol->getAsVariable()) {
constUnion* constArray = tVar->getConstUnionPointer();
variable->shareConstPointer(constArray);
} else {
error(line, "expected variable", initializer->getAsSymbolNode()->getSymbol().c_str(), "");
return true;
}
} else {
error(line, " cannot assign to", "=", "'%s'", variable->getType().getCompleteString().c_str());
variable->getType().getQualifier().storage = EvqTemporary;

View File

@ -35,7 +35,7 @@
//
//
// Symbol table for parsing. Most functionaliy and main ideas
// Symbol table for parsing. Most functionaliy and main ideas
// are documented in the header file.
//
@ -76,7 +76,7 @@ void TType::buildMangledName(TString& mangledName)
mangledName += '-';
(*structure)[i].type->buildMangledName(mangledName);
}
default:
default:
break;
}
@ -98,7 +98,7 @@ void TType::buildMangledName(TString& mangledName)
}
int TType::getStructSize() const
{
{
if (!getStruct()) {
assert(false && "Not a struct");
return 0;
@ -107,7 +107,7 @@ int TType::getStructSize() const
if (structureSize == 0)
for (TTypeList::iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
structureSize += ((*tl).type)->getObjectSize();
return structureSize;
}
@ -115,7 +115,7 @@ int TType::getStructSize() const
// Dump functions.
//
void TVariable::dump(TInfoSink& infoSink) const
void TVariable::dump(TInfoSink& infoSink) const
{
infoSink.debug << getName().c_str() << ": " << type.getStorageQualifierString() << " " << type.getBasicString();
if (type.isArray()) {
@ -129,7 +129,7 @@ void TFunction::dump(TInfoSink &infoSink) const
infoSink.debug << getName().c_str() << ": " << returnType.getBasicString() << " " << getMangledName().c_str() << "\n";
}
void TSymbolTableLevel::dump(TInfoSink &infoSink) const
void TSymbolTableLevel::dump(TInfoSink &infoSink) const
{
tLevel::const_iterator it;
for (it = level.begin(); it != level.end(); ++it)
@ -170,18 +170,17 @@ TSymbolTableLevel::~TSymbolTableLevel()
// performance operation, and only intended for symbol tables that
// live across a large number of compiles.
//
void TSymbolTableLevel::relateToOperator(const char* name, TOperator op)
void TSymbolTableLevel::relateToOperator(const char* name, TOperator op)
{
tLevel::iterator it;
for (it = level.begin(); it != level.end(); ++it) {
if ((*it).second->isFunction()) {
TFunction* function = static_cast<TFunction*>((*it).second);
TFunction* function = (*it).second->getAsFunction();
if (function) {
if (function->getName() == name)
function->relateToOperator(op);
}
}
}
}
TSymbol::TSymbol(const TSymbol& copyOf)
{
@ -194,11 +193,11 @@ TVariable::TVariable(const TVariable& copyOf, TStructureMap& remapper) : TSymbol
type.copyType(copyOf.type, remapper);
userType = copyOf.userType;
// for builtIn symbol table level, unionArray and arrayInformation pointers should be NULL
assert(copyOf.arrayInformationType == 0);
assert(copyOf.arrayInformationType == 0);
arrayInformationType = 0;
if (copyOf.unionArray) {
assert(!copyOf.type.getStruct());
assert(!copyOf.type.getStruct());
assert(copyOf.type.getObjectSize() == 1);
unionArray = new constUnion[1];
unionArray[0] = copyOf.unionArray[0];
@ -206,7 +205,7 @@ TVariable::TVariable(const TVariable& copyOf, TStructureMap& remapper) : TSymbol
unionArray = 0;
}
TVariable* TVariable::clone(TStructureMap& remapper)
TVariable* TVariable::clone(TStructureMap& remapper)
{
TVariable *variable = new TVariable(*this, remapper);
@ -227,7 +226,7 @@ TFunction::TFunction(const TFunction& copyOf, const TStructureMap& remapper) : T
defined = copyOf.defined;
}
TFunction* TFunction::clone(TStructureMap& remapper)
TFunction* TFunction::clone(TStructureMap& remapper)
{
TFunction *function = new TFunction(*this, remapper);

View File

@ -65,6 +65,8 @@
//
// Symbol base class. (Can build functions or variables out of these...)
//
class TVariable;
class TFunction;
class TSymbol {
public:
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
@ -72,8 +74,8 @@ public:
virtual ~TSymbol() { /* don't delete name, it's from the pool */ }
const TString& getName() const { return *name; }
virtual const TString& getMangledName() const { return getName(); }
virtual bool isFunction() const { return false; }
virtual bool isVariable() const { return false; }
virtual TFunction* getAsFunction() { return 0; }
virtual TVariable* getAsVariable() { return 0; }
void setUniqueId(int id) { uniqueId = id; }
int getUniqueId() const { return uniqueId; }
virtual void dump(TInfoSink &infoSink) const = 0;
@ -99,7 +101,7 @@ class TVariable : public TSymbol {
public:
TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0), arrayInformationType(0) { }
virtual ~TVariable() { }
virtual bool isVariable() const { return true; }
virtual TVariable* getAsVariable() { return this; }
TType& getType() { return type; }
const TType& getType() const { return type; }
bool isUserType() const { return userType; }
@ -109,14 +111,14 @@ public:
virtual void dump(TInfoSink &infoSink) const;
constUnion* getConstPointer() {
constUnion* getConstUnionPointer() {
if (!unionArray)
unionArray = new constUnion[type.getObjectSize()];
return unionArray;
}
constUnion* getConstPointer() const { return unionArray; }
constUnion* getConstUnionPointer() const { return unionArray; }
void shareConstPointer( constUnion *constArray)
{
@ -166,7 +168,7 @@ public:
defined(false) { }
TFunction(const TFunction&, const TStructureMap& remapper);
virtual ~TFunction();
virtual bool isFunction() const { return true; }
virtual TFunction* getAsFunction() { return this; }
void addParameter(TParameter& p)
{

View File

@ -541,11 +541,12 @@ int PaReservedWord()
int PaIdentOrType(TString& id, TParseContext& parseContextLocal, TSymbol*& symbol)
{
symbol = parseContextLocal.symbolTable.find(id);
if (parseContextLocal.lexAfterType == false && symbol && symbol->isVariable()) {
TVariable* variable = static_cast<TVariable*>(symbol);
if (variable->isUserType()) {
parseContextLocal.lexAfterType = true;
return TYPE_NAME;
if (parseContextLocal.lexAfterType == false && symbol) {
if (TVariable* variable = symbol->getAsVariable()) {
if (variable->isUserType()) {
parseContextLocal.lexAfterType = true;
return TYPE_NAME;
}
}
}

View File

@ -217,26 +217,24 @@ Jutta Degener, 1995
variable_identifier
: IDENTIFIER {
// The symbol table search was done in the lexical phase
const TSymbol* symbol = $1.symbol;
const TVariable* variable;
if (symbol == 0) {
TVariable* fakeVariable = new TVariable($1.string, TType(EbtVoid));
variable = fakeVariable;
} else {
// This identifier can only be a variable type symbol
if (! symbol->isVariable()) {
parseContext.error($1.line, "variable expected", $1.string->c_str(), "");
parseContext.recover();
}
variable = static_cast<const TVariable*>(symbol);
// The symbol table search was done in the lexical phase, but
// if this is a new symbol, it won't find it, which is okay at this
// point in the grammar.
TSymbol* symbol = $1.symbol;
const TVariable* variable = symbol ? symbol->getAsVariable() : 0;
if (symbol && ! variable) {
parseContext.error($1.line, "variable name expected", $1.string->c_str(), "");
parseContext.recover();
}
if (! variable)
variable = new TVariable($1.string, TType(EbtVoid));
// don't delete $1.string, it's used by error recovery, and the pool
// pop will reclaim the memory
if (variable->getType().getQualifier().storage == EvqConst ) {
constUnion* constArray = variable->getConstPointer();
constUnion* constArray = variable->getConstUnionPointer();
TType t(variable->getType());
$$ = parseContext.intermediate.addConstantUnion(constArray, t, $1.line);
} else
@ -1201,7 +1199,8 @@ function_prototype
//
// Redeclarations are allowed. But, return types and parameter qualifiers must match.
//
TFunction* prevDec = static_cast<TFunction*>(parseContext.symbolTable.find($1->getMangledName()));
TSymbol* symbol = parseContext.symbolTable.find($1->getMangledName());
TFunction* prevDec = symbol ? symbol->getAsFunction() : 0;
if (prevDec) {
if (prevDec->getReturnType() != $1->getReturnType()) {
parseContext.error($2.line, "overloaded functions must have the same return type", $1->getReturnType().getBasicString(), "");
@ -2460,10 +2459,15 @@ type_specifier_nonarray
// This is for user defined type names. The lexical phase looked up the
// type.
//
const TType& structure = static_cast<const TVariable*>($1.symbol)->getType();
$$.init($1.line, parseContext.symbolTable.atGlobalLevel());
$$.type = EbtStruct;
$$.userDef = &structure;
if (TVariable* variable = ($1.symbol)->getAsVariable()) {
const TType& structure = variable->getType();
$$.init($1.line, parseContext.symbolTable.atGlobalLevel());
$$.type = EbtStruct;
$$.userDef = &structure;
} else {
parseContext.error($1.line, "expected type name", $1.string->c_str(), "");
parseContext.recover();
}
}
;
@ -2876,20 +2880,35 @@ external_declaration
function_definition
: function_prototype {
TFunction& function = *($1.function);
TFunction* prevDec = static_cast<TFunction*>(parseContext.symbolTable.find(function.getMangledName()));
TSymbol* symbol = parseContext.symbolTable.find(function.getMangledName());
TFunction* prevDec = symbol ? symbol->getAsFunction() : 0;
if (! prevDec) {
parseContext.error($1.line, "can't find function name", function.getName().c_str(), "");
parseContext.recover();
}
//
// Note: 'prevDec' could be 'function' if this is the first time we've seen function
// as it would have just been put in the symbol table. Otherwise, we're looking up
// an earlier occurance.
//
if (prevDec->isDefined()) {
if (prevDec && prevDec->isDefined()) {
//
// Then this function already has a body.
//
parseContext.error($1.line, "function already has a body", function.getName().c_str(), "");
parseContext.recover();
}
prevDec->setDefined();
if (prevDec) {
prevDec->setDefined();
//
// Remember the return type for later checking for RETURN statements.
//
parseContext.currentFunctionType = &(prevDec->getReturnType());
} else
parseContext.currentFunctionType = new TType(EbtVoid);
parseContext.functionReturnsValue = false;
//
// Raise error message if main function takes any parameters or return anything other than void
@ -2910,12 +2929,6 @@ function_definition
//
parseContext.symbolTable.push();
//
// Remember the return type for later checking for RETURN statements.
//
parseContext.currentFunctionType = &(prevDec->getReturnType());
parseContext.functionReturnsValue = false;
//
// Insert parameters into the symbol table.
// If the parameter has no name, it's not an error, just don't insert it