Whole stack: Fix stale types in the AST linker object nodes, fixing #557.
Rationalizes the entire tracking of the linker object nodes, effecting GLSL, HLSL, and SPIR-V, to allow tracked objects to be fully edited before their type snapshot for linker objects. Should only effect things when the rest of the AST contained no reference to the symbol, because normal AST nodes were not stale. Also will only effect such objects when their types were edited.
This commit is contained in:
parent
e5e58cfee3
commit
d3f1122a44
107 changed files with 630 additions and 560 deletions
|
|
@ -221,16 +221,37 @@ void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op,
|
|||
error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str());
|
||||
}
|
||||
|
||||
// Add a linkage symbol node for 'symbol', which
|
||||
// must have its type fully edited, as this will snapshot the type.
|
||||
// It is okay if symbol becomes invalid before finish().
|
||||
void TParseContextBase::trackLinkage(TSymbol& symbol)
|
||||
{
|
||||
if (!parsingBuiltins)
|
||||
intermediate.addSymbolLinkageNode(linkage, symbol);
|
||||
}
|
||||
|
||||
// Add 'symbol' to the list of deferred linkage symbols, which
|
||||
// are later processed in finish(), at which point the symbol
|
||||
// must still be valid.
|
||||
// It is okay if the symbol's type will be subsequently edited.
|
||||
void TParseContextBase::trackLinkageDeferred(TSymbol& symbol)
|
||||
{
|
||||
if (!parsingBuiltins)
|
||||
linkageSymbols.push_back(&symbol);
|
||||
}
|
||||
|
||||
// Make a shared symbol have a non-shared version that can be edited by the current
|
||||
// compile, such that editing its type will not change the shared version and will
|
||||
// effect all nodes sharing it.
|
||||
// effect all nodes already sharing it (non-shallow type),
|
||||
// or adopting its full type after being edited (shallow type).
|
||||
void TParseContextBase::makeEditable(TSymbol*& symbol)
|
||||
{
|
||||
// copyUp() does a deep copy of the type.
|
||||
symbol = symbolTable.copyUp(symbol);
|
||||
|
||||
// Save it in the AST for linker use.
|
||||
intermediate.addSymbolLinkageNode(linkage, *symbol);
|
||||
// Save it (deferred, so it can be edited first) in the AST for linker use.
|
||||
if (symbol)
|
||||
trackLinkageDeferred(*symbol);
|
||||
}
|
||||
|
||||
// Return a writable version of the variable 'name'.
|
||||
|
|
@ -242,7 +263,7 @@ TVariable* TParseContextBase::getEditableVariable(const char* name)
|
|||
{
|
||||
bool builtIn;
|
||||
TSymbol* symbol = symbolTable.find(name, &builtIn);
|
||||
|
||||
|
||||
assert(symbol != nullptr);
|
||||
if (symbol == nullptr)
|
||||
return nullptr;
|
||||
|
|
@ -434,7 +455,7 @@ bool TParseContextBase::insertGlobalUniformBlock()
|
|||
// This is the first request; we need a normal symbol table insert
|
||||
inserted = symbolTable.insert(*globalUniformBlock);
|
||||
if (inserted)
|
||||
intermediate.addSymbolLinkageNode(linkage, *globalUniformBlock);
|
||||
trackLinkageDeferred(*globalUniformBlock);
|
||||
} else if (firstNewMember <= numMembers) {
|
||||
// This is a follow-on request; we need to amend the first insert
|
||||
inserted = symbolTable.amend(*globalUniformBlock, firstNewMember);
|
||||
|
|
@ -448,4 +469,14 @@ bool TParseContextBase::insertGlobalUniformBlock()
|
|||
return inserted;
|
||||
}
|
||||
|
||||
void TParseContextBase::finish()
|
||||
{
|
||||
if (!parsingBuiltins) {
|
||||
// Transfer te linkage symbols to AST nodes
|
||||
for (auto i = linkageSymbols.begin(); i != linkageSymbols.end(); ++i)
|
||||
intermediate.addSymbolLinkageNode(linkage, **i);
|
||||
intermediate.addSymbolLinkageNodes(linkage, getLanguage(), symbolTable);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
||||
|
|
|
|||
|
|
@ -50,15 +50,12 @@ namespace glslang {
|
|||
TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins,
|
||||
int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
|
||||
TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) :
|
||||
TParseContextBase(symbolTable, interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
|
||||
TParseContextBase(symbolTable, interm, parsingBuiltins, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
|
||||
contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0),
|
||||
inMain(false), postMainReturn(false), currentFunctionType(nullptr), blockName(nullptr),
|
||||
limits(resources.limits), parsingBuiltins(parsingBuiltins),
|
||||
limits(resources.limits),
|
||||
atomicUintOffsets(nullptr), anyIndexLimits(false)
|
||||
{
|
||||
// ensure we always have a linkage node, even if empty, to simplify tree topology algorithms
|
||||
linkage = new TIntermAggregate;
|
||||
|
||||
// decide whether precision qualifiers should be ignored or respected
|
||||
if (profile == EEsProfile || spvVersion.vulkan > 0) {
|
||||
precisionManager.respectPrecisionQualifiers();
|
||||
|
|
@ -184,8 +181,8 @@ bool TParseContext::parseShaderStrings(TPpContext& ppContext, TInputScanner& inp
|
|||
currentScanner = &input;
|
||||
ppContext.setInput(input, versionWillBeError);
|
||||
yyparse(this);
|
||||
if (! parsingBuiltins)
|
||||
finalErrorCheck();
|
||||
|
||||
finish();
|
||||
|
||||
return numErrors == 0;
|
||||
}
|
||||
|
|
@ -3093,7 +3090,7 @@ void TParseContext::arrayDimMerge(TType& type, const TArraySizes* sizes)
|
|||
// Do all the semantic checking for declaring or redeclaring an array, with and
|
||||
// without a size, and make the right changes to the symbol table.
|
||||
//
|
||||
void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, const TType& type, TSymbol*& symbol, bool& newDeclaration)
|
||||
void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, const TType& type, TSymbol*& symbol)
|
||||
{
|
||||
if (symbol == nullptr) {
|
||||
bool currentScope;
|
||||
|
|
@ -3111,7 +3108,8 @@ void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, con
|
|||
//
|
||||
symbol = new TVariable(&identifier, type);
|
||||
symbolTable.insert(*symbol);
|
||||
newDeclaration = true;
|
||||
if (symbolTable.atGlobalLevel())
|
||||
trackLinkageDeferred(*symbol);
|
||||
|
||||
if (! symbolTable.atBuiltInLevel()) {
|
||||
if (isIoResizeArray(type)) {
|
||||
|
|
@ -3271,7 +3269,8 @@ void TParseContext::nonInitConstCheck(const TSourceLoc& loc, TString& identifier
|
|||
//
|
||||
// Returns a redeclared and type-modified variable if a redeclarated occurred.
|
||||
//
|
||||
TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TString& identifier, const TQualifier& qualifier, const TShaderQualifiers& publicType, bool& newDeclaration)
|
||||
TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TString& identifier,
|
||||
const TQualifier& qualifier, const TShaderQualifiers& publicType)
|
||||
{
|
||||
if (! builtInName(identifier) || symbolTable.atBuiltInLevel() || ! symbolTable.atGlobalLevel())
|
||||
return nullptr;
|
||||
|
|
@ -3318,11 +3317,8 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS
|
|||
// If it wasn't at a built-in level, then it's already been redeclared;
|
||||
// that is, this is a redeclaration of a redeclaration; reuse that initial
|
||||
// redeclaration. Otherwise, make the new one.
|
||||
if (builtIn) {
|
||||
// Copy the symbol up to make a writable version
|
||||
if (builtIn)
|
||||
makeEditable(symbol);
|
||||
newDeclaration = true;
|
||||
}
|
||||
|
||||
// Now, modify the type of the copy, as per the type of the current redeclaration.
|
||||
|
||||
|
|
@ -3540,7 +3536,7 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
|
|||
fixIoArraySize(loc, block->getWritableType());
|
||||
|
||||
// Save it in the AST for linker use.
|
||||
intermediate.addSymbolLinkageNode(linkage, *block);
|
||||
trackLinkageDeferred(*block);
|
||||
}
|
||||
|
||||
void TParseContext::paramCheckFix(const TSourceLoc& loc, const TStorageQualifier& qualifier, TType& type)
|
||||
|
|
@ -3794,8 +3790,13 @@ void TParseContext::limitCheck(const TSourceLoc& loc, int value, const char* lim
|
|||
//
|
||||
// Do any additional error checking, etc., once we know the parsing is done.
|
||||
//
|
||||
void TParseContext::finalErrorCheck()
|
||||
void TParseContext::finish()
|
||||
{
|
||||
TParseContextBase::finish();
|
||||
|
||||
if (parsingBuiltins)
|
||||
return;
|
||||
|
||||
// Check on array indexes for ES 2.0 (version 100) limitations.
|
||||
for (size_t i = 0; i < needsIndexLimitationChecking.size(); ++i)
|
||||
constantIndexExpressionCheck(needsIndexLimitationChecking[i]);
|
||||
|
|
@ -4971,8 +4972,7 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
|
|||
error(loc, "can only apply depth layout to gl_FragDepth", "layout qualifier", "");
|
||||
|
||||
// Check for redeclaration of built-ins and/or attempting to declare a reserved name
|
||||
bool newDeclaration = false; // true if a new entry gets added to the symbol table
|
||||
TSymbol* symbol = redeclareBuiltinVariable(loc, identifier, type.getQualifier(), publicType.shaderQualifiers, newDeclaration);
|
||||
TSymbol* symbol = redeclareBuiltinVariable(loc, identifier, type.getQualifier(), publicType.shaderQualifiers);
|
||||
if (symbol == nullptr)
|
||||
reservedErrorCheck(loc, identifier);
|
||||
|
||||
|
|
@ -4990,7 +4990,7 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
|
|||
arrayUnsizedCheck(loc, type.getQualifier(), &type.getArraySizes(), initializer != nullptr, false);
|
||||
|
||||
if (! arrayQualifierError(loc, type.getQualifier()) && ! arrayError(loc, type))
|
||||
declareArray(loc, identifier, type, symbol, newDeclaration);
|
||||
declareArray(loc, identifier, type, symbol);
|
||||
|
||||
if (initializer) {
|
||||
profileRequires(loc, ENoProfile, 120, E_GL_3DL_array_objects, "initializer");
|
||||
|
|
@ -4999,7 +4999,7 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
|
|||
} else {
|
||||
// non-array case
|
||||
if (symbol == nullptr)
|
||||
symbol = declareNonArray(loc, identifier, type, newDeclaration);
|
||||
symbol = declareNonArray(loc, identifier, type);
|
||||
else if (type != symbol->getType())
|
||||
error(loc, "cannot change the type of", "redeclaration", symbol->getName().c_str());
|
||||
}
|
||||
|
|
@ -5022,10 +5022,6 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
|
|||
layoutObjectCheck(loc, *symbol);
|
||||
fixOffset(loc, *symbol);
|
||||
|
||||
// see if it's a linker-level object to track
|
||||
if (newDeclaration && symbolTable.atGlobalLevel())
|
||||
intermediate.addSymbolLinkageNode(linkage, *symbol);
|
||||
|
||||
return initNode;
|
||||
}
|
||||
|
||||
|
|
@ -5061,20 +5057,22 @@ TVariable* TParseContext::makeInternalVariable(const char* name, const TType& ty
|
|||
//
|
||||
// Return the successfully declared variable.
|
||||
//
|
||||
TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, TString& identifier, TType& type, bool& newDeclaration)
|
||||
TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, TString& identifier, TType& type)
|
||||
{
|
||||
// make a new variable
|
||||
TVariable* variable = new TVariable(&identifier, type);
|
||||
|
||||
ioArrayCheck(loc, type, identifier);
|
||||
|
||||
// add variable to symbol table
|
||||
if (! symbolTable.insert(*variable)) {
|
||||
error(loc, "redefinition", variable->getName().c_str(), "");
|
||||
return nullptr;
|
||||
} else {
|
||||
newDeclaration = true;
|
||||
if (symbolTable.insert(*variable)) {
|
||||
if (symbolTable.atGlobalLevel())
|
||||
trackLinkageDeferred(*variable);
|
||||
return variable;
|
||||
}
|
||||
|
||||
error(loc, "redefinition", variable->getName().c_str(), "");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -5731,7 +5729,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
|
|||
fixIoArraySize(loc, variable.getWritableType());
|
||||
|
||||
// Save it in the AST for linker use.
|
||||
intermediate.addSymbolLinkageNode(linkage, variable);
|
||||
trackLinkageDeferred(variable);
|
||||
}
|
||||
|
||||
// Do all block-declaration checking regarding the combination of in/out/uniform/buffer
|
||||
|
|
|
|||
|
|
@ -73,13 +73,16 @@ typedef std::set<int> TIdSetType;
|
|||
//
|
||||
class TParseContextBase : public TParseVersions {
|
||||
public:
|
||||
TParseContextBase(TSymbolTable& symbolTable, TIntermediate& interm, int version,
|
||||
TParseContextBase(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins, int version,
|
||||
EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
|
||||
TInfoSink& infoSink, bool forwardCompatible, EShMessages messages)
|
||||
: TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
|
||||
symbolTable(symbolTable),
|
||||
linkage(nullptr), scanContext(nullptr), ppContext(nullptr),
|
||||
globalUniformBlock(nullptr) { }
|
||||
parsingBuiltins(parsingBuiltins), scanContext(nullptr), ppContext(nullptr),
|
||||
globalUniformBlock(nullptr)
|
||||
{
|
||||
linkage = new TIntermAggregate;
|
||||
}
|
||||
virtual ~TParseContextBase() { }
|
||||
|
||||
virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
|
||||
|
|
@ -94,7 +97,6 @@ public:
|
|||
virtual void setLimits(const TBuiltInResource&) = 0;
|
||||
|
||||
EShLanguage getLanguage() const { return language; }
|
||||
TIntermAggregate*& getLinkage() { return linkage; }
|
||||
void setScanContext(TScanContext* c) { scanContext = c; }
|
||||
TScanContext* getScanContext() const { return scanContext; }
|
||||
void setPpContext(TPpContext* c) { ppContext = c; }
|
||||
|
|
@ -150,7 +152,8 @@ protected:
|
|||
TParseContextBase(TParseContextBase&);
|
||||
TParseContextBase& operator=(TParseContextBase&);
|
||||
|
||||
TIntermAggregate* linkage; // aggregate node of objects the linker may need, if not referenced by the rest of the AST
|
||||
const bool parsingBuiltins; // true if parsing built-in symbols/functions
|
||||
TVector<TSymbol*> linkageSymbols; // these need to be transferred to 'linkage', after all editing is done
|
||||
TScanContext* scanContext;
|
||||
TPpContext* ppContext;
|
||||
|
||||
|
|
@ -177,8 +180,14 @@ protected:
|
|||
virtual void outputMessage(const TSourceLoc&, const char* szReason, const char* szToken,
|
||||
const char* szExtraInfoFormat, TPrefixType prefix,
|
||||
va_list args);
|
||||
virtual void trackLinkage(TSymbol& symbol);
|
||||
virtual void trackLinkageDeferred(TSymbol& symbol);
|
||||
virtual void makeEditable(TSymbol*&);
|
||||
virtual TVariable* getEditableVariable(const char* name);
|
||||
virtual void finish();
|
||||
|
||||
private:
|
||||
TIntermAggregate* linkage;
|
||||
};
|
||||
|
||||
//
|
||||
|
|
@ -314,7 +323,7 @@ public:
|
|||
void precisionQualifierCheck(const TSourceLoc&, TBasicType, TQualifier&);
|
||||
void parameterTypeCheck(const TSourceLoc&, TStorageQualifier qualifier, const TType& type);
|
||||
bool containsFieldWithBasicType(const TType& type ,TBasicType basicType);
|
||||
TSymbol* redeclareBuiltinVariable(const TSourceLoc&, const TString&, const TQualifier&, const TShaderQualifiers&, bool& newDeclaration);
|
||||
TSymbol* redeclareBuiltinVariable(const TSourceLoc&, const TString&, const TQualifier&, const TShaderQualifiers&);
|
||||
void redeclareBuiltinBlock(const TSourceLoc&, TTypeList& typeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes);
|
||||
void paramCheckFix(const TSourceLoc&, const TStorageQualifier&, TType& type);
|
||||
void paramCheckFix(const TSourceLoc&, const TQualifier&, TType& type);
|
||||
|
|
@ -368,11 +377,11 @@ protected:
|
|||
void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type);
|
||||
void inheritGlobalDefaults(TQualifier& dst) const;
|
||||
TVariable* makeInternalVariable(const char* name, const TType&) const;
|
||||
TVariable* declareNonArray(const TSourceLoc&, TString& identifier, TType&, bool& newDeclaration);
|
||||
void declareArray(const TSourceLoc&, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration);
|
||||
TVariable* declareNonArray(const TSourceLoc&, TString& identifier, TType&);
|
||||
void declareArray(const TSourceLoc&, TString& identifier, const TType&, TSymbol*&);
|
||||
TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable);
|
||||
TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer);
|
||||
void finalErrorCheck();
|
||||
void finish() override;
|
||||
|
||||
public:
|
||||
//
|
||||
|
|
@ -401,7 +410,6 @@ protected:
|
|||
TParseContext(TParseContext&);
|
||||
TParseContext& operator=(TParseContext&);
|
||||
|
||||
const bool parsingBuiltins; // true if parsing built-in symbols/functions
|
||||
static const int maxSamplerIndex = EsdNumDims * (EbtNumTypes * (2 * 2 * 2 * 2 * 2)); // see computeSamplerTypeIndex()
|
||||
TPrecisionQualifier defaultSamplerPrecision[maxSamplerIndex];
|
||||
TPrecisionManager precisionManager;
|
||||
|
|
|
|||
|
|
@ -947,7 +947,6 @@ struct DoFullParse{
|
|||
// Parse the full shader.
|
||||
if (! parseContext.parseShaderStrings(ppContext, fullInput, versionWillBeError))
|
||||
success = false;
|
||||
intermediate.addSymbolLinkageNodes(parseContext.getLinkage(), parseContext.getLanguage(), symbolTable);
|
||||
|
||||
if (success && intermediate.getTreeRoot()) {
|
||||
if (optLevel == EShOptNoGeneration)
|
||||
|
|
|
|||
|
|
@ -260,7 +260,6 @@ public:
|
|||
|
||||
// Linkage related
|
||||
void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
|
||||
void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
|
||||
void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&);
|
||||
|
||||
bool setInvocations(int i)
|
||||
|
|
@ -396,6 +395,7 @@ protected:
|
|||
bool promote(TIntermOperator*);
|
||||
bool promoteUnary(TIntermUnary&);
|
||||
bool promoteBinary(TIntermBinary&);
|
||||
void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
|
||||
|
||||
const EShLanguage language; // stage, known at construction time
|
||||
EShSource source; // source language, known a bit later
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue