Infrastructure: Generalize and broaden per-variable extension checking.
diff --git a/glslang/MachineIndependent/Initialize.cpp b/glslang/MachineIndependent/Initialize.cpp
index a20d3be..5fa0f2e 100755
--- a/glslang/MachineIndependent/Initialize.cpp
+++ b/glslang/MachineIndependent/Initialize.cpp
@@ -7737,11 +7737,12 @@
static void SpecialQualifier(const char* name, TStorageQualifier qualifier, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
{
TSymbol* symbol = symbolTable.find(name);
- if (symbol) {
- TQualifier& symQualifier = symbol->getWritableType().getQualifier();
- symQualifier.storage = qualifier;
- symQualifier.builtIn = builtIn;
- }
+ if (symbol == nullptr)
+ return;
+
+ TQualifier& symQualifier = symbol->getWritableType().getQualifier();
+ symQualifier.storage = qualifier;
+ symQualifier.builtIn = builtIn;
}
//
@@ -7757,7 +7758,7 @@
static void BuiltInVariable(const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
{
TSymbol* symbol = symbolTable.find(name);
- if (! symbol)
+ if (symbol == nullptr)
return;
TQualifier& symQualifier = symbol->getWritableType().getQualifier();
@@ -7774,7 +7775,7 @@
static void BuiltInVariable(const char* blockName, const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
{
TSymbol* symbol = symbolTable.find(blockName);
- if (! symbol)
+ if (symbol == nullptr)
return;
TTypeList& structure = *symbol->getWritableType().getWritableStruct();
@@ -8076,15 +8077,16 @@
// gl_PointSize, when it needs to be tied to an extension, is always a member of a block.
// (Sometimes with an instance name, sometimes anonymous).
- // However, the current automatic extension scheme does not work per block member,
- // so for now check when parsing.
- //
- // if (profile == EEsProfile) {
- // if (language == EShLangGeometry)
- // symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_geometry_point_size, AEP_geometry_point_size);
- // else if (language == EShLangTessEvaluation || language == EShLangTessControl)
- // symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
- //}
+ if (profile == EEsProfile) {
+ if (language == EShLangGeometry) {
+ symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_geometry_point_size, AEP_geometry_point_size);
+ symbolTable.setVariableExtensions("gl_in", "gl_PointSize", Num_AEP_geometry_point_size, AEP_geometry_point_size);
+ } else if (language == EShLangTessEvaluation || language == EShLangTessControl) {
+ // gl_in tessellation settings of gl_PointSize are in the context-dependent paths
+ symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
+ symbolTable.setVariableExtensions("gl_out", "gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
+ }
+ }
if ((profile != EEsProfile && version >= 140) ||
(profile == EEsProfile && version >= 310)) {
@@ -9511,6 +9513,12 @@
BuiltInVariable("gl_in", "gl_BackSecondaryColor", EbvBackSecondaryColor, symbolTable);
BuiltInVariable("gl_in", "gl_TexCoord", EbvTexCoord, symbolTable);
BuiltInVariable("gl_in", "gl_FogFragCoord", EbvFogFragCoord, symbolTable);
+
+ // extension requirements
+ if (profile == EEsProfile) {
+ symbolTable.setVariableExtensions("gl_in", "gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
+ }
+
break;
default:
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index d16dc99..ea50391 100755
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -312,9 +312,6 @@
if (anon) {
// It was a member of an anonymous container.
- // The "getNumExtensions()" mechanism above doesn't yet work for block members
- blockMemberExtensionCheck(loc, nullptr, *string);
-
// Create a subtree for its dereference.
variable = anon->getAnonContainer().getAsVariable();
TIntermTyped* container = intermediate.addSymbol(*variable, loc);
@@ -834,7 +831,7 @@
if (base->getType().getQualifier().isFrontEndConstant())
result = intermediate.foldDereference(base, member, loc);
else {
- blockMemberExtensionCheck(loc, base, field);
+ blockMemberExtensionCheck(loc, base, member, field);
TIntermTyped* index = intermediate.addConstantUnion(member, loc);
result = intermediate.addIndex(EOpIndexDirectStruct, base, index, loc);
result->setType(*(*fields)[member].type);
@@ -857,14 +854,30 @@
return result;
}
-void TParseContext::blockMemberExtensionCheck(const TSourceLoc& loc, const TIntermTyped* /*base*/, const TString& field)
+void TParseContext::blockMemberExtensionCheck(const TSourceLoc& loc, const TIntermTyped* base, int member, const TString& memberName)
{
- if (profile == EEsProfile && field == "gl_PointSize") {
- if (language == EShLangGeometry)
- requireExtensions(loc, Num_AEP_geometry_point_size, AEP_geometry_point_size, "gl_PointSize");
- else if (language == EShLangTessControl || language == EShLangTessEvaluation)
- requireExtensions(loc, Num_AEP_tessellation_point_size, AEP_tessellation_point_size, "gl_PointSize");
- }
+ // a block that needs extension checking is either 'base', or if arrayed,
+ // one level removed to the left
+ const TIntermSymbol* baseSymbol = nullptr;
+ if (base->getAsBinaryNode() == nullptr)
+ baseSymbol = base->getAsSymbolNode();
+ else
+ baseSymbol = base->getAsBinaryNode()->getLeft()->getAsSymbolNode();
+ if (baseSymbol == nullptr)
+ return;
+ const TSymbol* symbol = symbolTable.find(baseSymbol->getName());
+ if (symbol == nullptr)
+ return;
+ const TVariable* variable = symbol->getAsVariable();
+ if (variable == nullptr)
+ return;
+ if (!variable->hasMemberExtensions())
+ return;
+
+ // We now have a variable that is the base of a dot reference
+ // with members that need extension checking.
+ if (variable->getNumMemberExtensions(member) > 0)
+ requireExtensions(loc, variable->getNumMemberExtensions(member), variable->getMemberExtensions(member), memberName.c_str());
}
//
diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h
index 768a241..5b7d430 100755
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -306,7 +306,7 @@
TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right);
TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode);
TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field);
- void blockMemberExtensionCheck(const TSourceLoc&, const TIntermTyped* base, const TString& field);
+ void blockMemberExtensionCheck(const TSourceLoc&, const TIntermTyped* base, int member, const TString& memberName);
TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);
diff --git a/glslang/MachineIndependent/SymbolTable.cpp b/glslang/MachineIndependent/SymbolTable.cpp
index c164ac8..0e33116 100755
--- a/glslang/MachineIndependent/SymbolTable.cpp
+++ b/glslang/MachineIndependent/SymbolTable.cpp
@@ -287,19 +287,25 @@
{
type.deepCopy(copyOf.type);
userType = copyOf.userType;
- numExtensions = 0;
- extensions = 0;
- if (copyOf.numExtensions != 0)
- setExtensions(copyOf.numExtensions, copyOf.extensions);
+
+ // we don't support specialization-constant subtrees in cloned tables, only extensions
+ constSubtree = nullptr;
+ extensions = nullptr;
+ memberExtensions = nullptr;
+ if (copyOf.getNumExtensions() > 0)
+ setExtensions(copyOf.getNumExtensions(), copyOf.getExtensions());
+ if (copyOf.hasMemberExtensions()) {
+ for (int m = 0; m < copyOf.type.getStruct()->size(); ++m) {
+ if (copyOf.getNumMemberExtensions(m) > 0)
+ setMemberExtensions(m, copyOf.getNumMemberExtensions(m), copyOf.getMemberExtensions(m));
+ }
+ }
if (! copyOf.constArray.empty()) {
assert(! copyOf.type.isStruct());
TConstUnionArray newArray(copyOf.constArray, 0, copyOf.constArray.size());
constArray = newArray;
}
-
- // don't support specialization-constant subtrees in cloned tables
- constSubtree = nullptr;
}
TVariable* TVariable::clone() const
@@ -317,10 +323,9 @@
parameters.back().copyParam(copyOf.parameters[i]);
}
- numExtensions = 0;
- extensions = 0;
- if (copyOf.extensions != 0)
- setExtensions(copyOf.numExtensions, copyOf.extensions);
+ extensions = nullptr;
+ if (copyOf.getNumExtensions() > 0)
+ setExtensions(copyOf.getNumExtensions(), copyOf.getExtensions());
returnType.deepCopy(copyOf.returnType);
mangledName = copyOf.mangledName;
op = copyOf.op;
@@ -359,12 +364,12 @@
const TAnonMember* anon = iter->second->getAsAnonMember();
if (anon) {
// Insert all the anonymous members of this same container at once,
- // avoid inserting the other members in the future, once this has been done,
+ // avoid inserting the remaining members in the future, once this has been done,
// allowing them to all be part of the same new container.
if (! containerCopied[anon->getAnonId()]) {
TVariable* container = anon->getAnonContainer().clone();
container->changeName(NewPoolTString(""));
- // insert the whole container
+ // insert the container and all its members
symTableLevel->insert(*container, false);
containerCopied[anon->getAnonId()] = true;
}
diff --git a/glslang/MachineIndependent/SymbolTable.h b/glslang/MachineIndependent/SymbolTable.h
index a69d87e..5374052 100755
--- a/glslang/MachineIndependent/SymbolTable.h
+++ b/glslang/MachineIndependent/SymbolTable.h
@@ -79,10 +79,12 @@
class TFunction;
class TAnonMember;
+typedef TVector<const char*> TExtensionList;
+
class TSymbol {
public:
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
- explicit TSymbol(const TString *n) : name(n), numExtensions(0), extensions(0), writable(true) { }
+ explicit TSymbol(const TString *n) : name(n), extensions(0), writable(true) { }
virtual TSymbol* clone() const = 0;
virtual ~TSymbol() { } // rely on all symbol owned memory coming from the pool
@@ -104,17 +106,16 @@
virtual TType& getWritableType() = 0;
virtual void setUniqueId(int id) { uniqueId = id; }
virtual int getUniqueId() const { return uniqueId; }
- virtual void setExtensions(int num, const char* const exts[])
+ virtual void setExtensions(int numExts, const char* const exts[])
{
assert(extensions == 0);
- assert(num > 0);
- numExtensions = num;
- extensions = NewPoolObject(exts[0], num);
- for (int e = 0; e < num; ++e)
- extensions[e] = exts[e];
+ assert(numExts > 0);
+ extensions = NewPoolObject(extensions);
+ for (int e = 0; e < numExts; ++e)
+ extensions->push_back(exts[e]);
}
- virtual int getNumExtensions() const { return numExtensions; }
- virtual const char** getExtensions() const { return extensions; }
+ virtual int getNumExtensions() const { return extensions == nullptr ? 0 : (int)extensions->size(); }
+ virtual const char** getExtensions() const { return extensions->data(); }
virtual void dump(TInfoSink &infoSink) const = 0;
virtual bool isReadOnly() const { return ! writable; }
@@ -129,8 +130,7 @@
// For tracking what extensions must be present
// (don't use if correct version/profile is present).
- int numExtensions;
- const char** extensions; // an array of pointers to existing constant char strings
+ TExtensionList* extensions; // an array of pointers to existing constant char strings
//
// N.B.: Non-const functions that will be generally used should assert on this,
@@ -155,7 +155,9 @@
: TSymbol(name),
userType(uT),
constSubtree(nullptr),
- anonId(-1) { type.shallowCopy(t); }
+ memberExtensions(nullptr),
+ anonId(-1)
+ { type.shallowCopy(t); }
virtual TVariable* clone() const;
virtual ~TVariable() { }
@@ -172,6 +174,24 @@
virtual void setAnonId(int i) { anonId = i; }
virtual int getAnonId() const { return anonId; }
+ virtual void setMemberExtensions(int member, int numExts, const char* const exts[])
+ {
+ assert(type.isStruct());
+ assert(numExts > 0);
+ if (memberExtensions == nullptr) {
+ memberExtensions = NewPoolObject(memberExtensions);
+ memberExtensions->resize(type.getStruct()->size());
+ }
+ for (int e = 0; e < numExts; ++e)
+ (*memberExtensions)[member].push_back(exts[e]);
+ }
+ virtual bool hasMemberExtensions() const { return memberExtensions != nullptr; }
+ virtual int getNumMemberExtensions(int member) const
+ {
+ return memberExtensions == nullptr ? 0 : (int)(*memberExtensions)[member].size();
+ }
+ virtual const char** getMemberExtensions(int member) const { return (*memberExtensions)[member].data(); }
+
virtual void dump(TInfoSink &infoSink) const;
protected:
@@ -180,15 +200,14 @@
TType type;
bool userType;
+
// we are assuming that Pool Allocator will free the memory allocated to unionArray
// when this object is destroyed
- // TODO: these two should be a union
- // A variable could be a compile-time constant, or a specialization
- // constant, or neither, but never both.
- TConstUnionArray constArray; // for compile-time constant value
- TIntermTyped* constSubtree; // for specialization constant computation
- int anonId; // the ID used for anonymous blocks: TODO: see if uniqueId could serve a dual purpose
+ TConstUnionArray constArray; // for compile-time constant value
+ TIntermTyped* constSubtree; // for specialization constant computation
+ TVector<TExtensionList>* memberExtensions; // per-member extension list, allocated only when needed
+ int anonId; // the ID used for anonymous blocks: TODO: see if uniqueId could serve a dual purpose
};
//
@@ -325,7 +344,7 @@
//
class TAnonMember : public TSymbol {
public:
- TAnonMember(const TString* n, unsigned int m, const TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
+ TAnonMember(const TString* n, unsigned int m, TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
virtual TAnonMember* clone() const;
virtual ~TAnonMember() { }
@@ -346,6 +365,13 @@
return *types[memberNumber].type;
}
+ virtual void setExtensions(int numExts, const char* const exts[]) override
+ {
+ anonContainer.setMemberExtensions(memberNumber, numExts, exts);
+ }
+ virtual int getNumExtensions() const override { return anonContainer.getNumMemberExtensions(memberNumber); }
+ virtual const char** getExtensions() const override { return anonContainer.getMemberExtensions(memberNumber); }
+
virtual int getAnonId() const { return anonId; }
virtual void dump(TInfoSink &infoSink) const;
@@ -353,7 +379,7 @@
explicit TAnonMember(const TAnonMember&);
TAnonMember& operator=(const TAnonMember&);
- const TVariable& anonContainer;
+ TVariable& anonContainer;
unsigned int memberNumber;
int anonId;
};
@@ -789,11 +815,30 @@
table[level]->setFunctionExtensions(name, num, extensions);
}
- void setVariableExtensions(const char* name, int num, const char* const extensions[])
+ void setVariableExtensions(const char* name, int numExts, const char* const extensions[])
{
TSymbol* symbol = find(TString(name));
- if (symbol)
- symbol->setExtensions(num, extensions);
+ if (symbol == nullptr)
+ return;
+
+ symbol->setExtensions(numExts, extensions);
+ }
+
+ void setVariableExtensions(const char* blockName, const char* name, int numExts, const char* const extensions[])
+ {
+ TSymbol* symbol = find(TString(blockName));
+ if (symbol == nullptr)
+ return;
+ TVariable* variable = symbol->getAsVariable();
+ assert(variable != nullptr);
+
+ const TTypeList& structure = *variable->getAsVariable()->getType().getStruct();
+ for (int member = 0; member < (int)structure.size(); ++member) {
+ if (structure[member].type->getFieldName().compare(name) == 0) {
+ variable->setMemberExtensions(member, numExts, extensions);
+ return;
+ }
+ }
}
int getMaxSymbolId() { return uniqueId; }
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index d6dc2e8..3cb8587 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -653,10 +653,6 @@
return nullptr;
}
- // Error check for requiring specific extensions present.
- if (symbol && symbol->getNumExtensions())
- requireExtensions(loc, symbol->getNumExtensions(), symbol->getExtensions(), symbol->getName().c_str());
-
const TVariable* variable = nullptr;
const TAnonMember* anon = symbol ? symbol->getAsAnonMember() : nullptr;
TIntermTyped* node = nullptr;
@@ -5321,11 +5317,6 @@
// - a built-in function not mapped to an operator, or
// - a user function.
- // Error check for a function requiring specific extensions present.
- if (builtIn && fnCandidate->getNumExtensions())
- requireExtensions(loc, fnCandidate->getNumExtensions(), fnCandidate->getExtensions(),
- fnCandidate->getName().c_str());
-
// turn an implicit member-function resolution into an explicit call
TString callerName;
if (thisDepth == 0)