diff --git a/Install/Windows/glslangValidator.exe b/Install/Windows/glslangValidator.exe
index 9fd73c33..8fff1f69 100644
Binary files a/Install/Windows/glslangValidator.exe and b/Install/Windows/glslangValidator.exe differ
diff --git a/Test/150.vert b/Test/150.vert
new file mode 100644
index 00000000..cc7642c0
--- /dev/null
+++ b/Test/150.vert
@@ -0,0 +1,21 @@
+#version 150 core
+
+in vec4 iv4;
+
+uniform float ps;
+
+invariant gl_Position;
+
+void main()
+{
+ gl_Position = iv4;
+ gl_PointSize = ps;
+ gl_ClipDistance[2] = iv4.x;
+}
+
+float gl_ClipDistance[4];
+
+uniform foob {
+ int a[];
+};
+int a[5]; // ERROR, resizing user-block member
diff --git a/Test/300link.frag b/Test/300link.frag
new file mode 100644
index 00000000..5d39cc0f
--- /dev/null
+++ b/Test/300link.frag
@@ -0,0 +1,8 @@
+#version 300 es
+
+precision highp float;
+
+out vec4 color1;
+out vec4 color2;
+
+void main() {}
diff --git a/Test/300link2.frag b/Test/300link2.frag
new file mode 100644
index 00000000..7800ac9b
--- /dev/null
+++ b/Test/300link2.frag
@@ -0,0 +1,11 @@
+#version 300 es
+precision mediump float;
+in vec4 pos;
+
+layout(location = 1) out vec4 c;
+layout(location = 5) out vec4 p;
+layout(location = 9) out vec4 q[2];
+
+void main()
+{
+}
diff --git a/Test/300link3.frag b/Test/300link3.frag
new file mode 100644
index 00000000..410592c6
--- /dev/null
+++ b/Test/300link3.frag
@@ -0,0 +1,7 @@
+#version 300 es
+
+precision highp float;
+
+out vec4 color1;
+
+void main() {}
diff --git a/Test/410.geom b/Test/410.geom
new file mode 100644
index 00000000..2e5eeeb7
--- /dev/null
+++ b/Test/410.geom
@@ -0,0 +1,6 @@
+#version 410 core
+
+void main()
+{
+ gl_ViewportIndex = 7;
+}
diff --git a/Test/baseResults/150.vert.out b/Test/baseResults/150.vert.out
new file mode 100644
index 00000000..5d58342e
--- /dev/null
+++ b/Test/baseResults/150.vert.out
@@ -0,0 +1,33 @@
+Warning, version 150 is not yet complete; some version-specific features are present, but many are missing.
+ERROR: 0:13: 'gl_ClipDistance' : undeclared identifier
+ERROR: 0:13: 'gl_ClipDistance' : left of '[' is not of type array, matrix, or vector
+ERROR: 0:13: 'assign' : l-value required (can't modify a const)
+ERROR: 0:16: 'gl_' : reserved built-in name
+ERROR: 0:21: 'a' : cannot redeclare a user-block member array
+ERROR: 5 compilation errors. No code generated.
+
+ERROR: node is still EOpNull!
+0:9 Function Definition: main( (void)
+0:9 Function Parameters:
+0:11 Sequence
+0:11 move second child to first child (4-component vector of float)
+0:11 'gl_Position' (invariant gl_Position 4-component vector of float)
+0:11 'iv4' (in 4-component vector of float)
+0:12 move second child to first child (float)
+0:12 'gl_PointSize' (gl_PointSize float)
+0:12 'ps' (uniform float)
+0:13 move second child to first child (float)
+0:13 Constant:
+0:13 0.000000
+0:13 direct index (float)
+0:13 'iv4' (in 4-component vector of float)
+0:13 Constant:
+0:13 0 (const int)
+0:? Linker Objects
+0:? 'iv4' (in 4-component vector of float)
+0:? 'ps' (uniform float)
+0:? 'gl_ClipDistance' (4-element array of float)
+0:? '__anon__0' (layout(shared ) uniform block)
+0:? 'gl_VertexID' (gl_VertexId int)
+0:? 'gl_InstanceID' (gl_InstanceId int)
+
diff --git a/Test/baseResults/300link.frag.out b/Test/baseResults/300link.frag.out
new file mode 100644
index 00000000..7ce563a4
--- /dev/null
+++ b/Test/baseResults/300link.frag.out
@@ -0,0 +1,15 @@
+300link.frag
+
+0:? Sequence
+0:8 Function Definition: main( (void)
+0:8 Function Parameters:
+0:? Linker Objects
+0:? 'color1' (out highp 4-component vector of float)
+0:? 'color2' (out highp 4-component vector of float)
+
+
+Linked fragment stage:
+
+ERROR: Linking fragment stage: when more than one fragment shader output, all must have location qualifiers
+
+
diff --git a/Test/baseResults/300link2.frag.out b/Test/baseResults/300link2.frag.out
new file mode 100644
index 00000000..bf264ecb
--- /dev/null
+++ b/Test/baseResults/300link2.frag.out
@@ -0,0 +1,16 @@
+300link2.frag
+
+0:? Sequence
+0:9 Function Definition: main( (void)
+0:9 Function Parameters:
+0:? Linker Objects
+0:? 'pos' (smooth in mediump 4-component vector of float)
+0:? 'c' (layout(location=1 ) out mediump 4-component vector of float)
+0:? 'p' (layout(location=5 ) out mediump 4-component vector of float)
+0:? 'q' (layout(location=9 ) out 2-element array of mediump 4-component vector of float)
+
+
+Linked fragment stage:
+
+
+
diff --git a/Test/baseResults/300link3.frag.out b/Test/baseResults/300link3.frag.out
new file mode 100644
index 00000000..1317a2d6
--- /dev/null
+++ b/Test/baseResults/300link3.frag.out
@@ -0,0 +1,13 @@
+300link3.frag
+
+0:? Sequence
+0:7 Function Definition: main( (void)
+0:7 Function Parameters:
+0:? Linker Objects
+0:? 'color1' (out highp 4-component vector of float)
+
+
+Linked fragment stage:
+
+
+
diff --git a/Test/baseResults/410.geom.out b/Test/baseResults/410.geom.out
new file mode 100644
index 00000000..a937b844
--- /dev/null
+++ b/Test/baseResults/410.geom.out
@@ -0,0 +1,14 @@
+Warning, version 410 is not yet complete; some version-specific features are present, but many are missing.
+ERROR: 0:5: 'gl_ViewportIndex' : undeclared identifier
+ERROR: 1 compilation errors. No code generated.
+
+ERROR: node is still EOpNull!
+0:3 Function Definition: main( (void)
+0:3 Function Parameters:
+0:5 Sequence
+0:5 move second child to first child (float)
+0:5 'gl_ViewportIndex' (float)
+0:5 Constant:
+0:5 7.000000
+0:? Linker Objects
+
diff --git a/Test/runtests b/Test/runtests
index b9e9f714..0bde19ee 100644
--- a/Test/runtests
+++ b/Test/runtests
@@ -38,6 +38,9 @@ runLinkTest mains1.frag mains2.frag noMain1.geom noMain2.geom
runLinkTest noMain.vert mains.frag
runLinkTest link1.frag link2.frag link3.frag
runLinkTest recurse1.vert recurse1.frag recurse2.frag
+runLinkTest 300link.frag
+runLinkTest 300link2.frag
+runLinkTest 300link3.frag
#
# multi-threaded test
diff --git a/Test/testlist b/Test/testlist
index 26e7b00e..b6b3ad73 100644
--- a/Test/testlist
+++ b/Test/testlist
@@ -12,6 +12,7 @@ versionsErrors.vert
120.frag
130.frag
140.frag
+150.vert
150.geom
precision.frag
precision.vert
@@ -52,6 +53,7 @@ numeral.frag
400.geom
400.tesc
400.tese
+410.geom
420.tese
430.comp
dce.frag
diff --git a/Todo.txt b/Todo.txt
index a989f64f..6c8cb692 100644
--- a/Todo.txt
+++ b/Todo.txt
@@ -8,25 +8,25 @@ Link Validation
Cross-stage linking
- type consistency check of uniform and ins <-> outs, both variables and blocks, stage-specific arrayness matching
- location/binding/index check
- - matching initializers for uniforms
- mixed es/non-es profiles
- statically consumed input not produced by previous stage
- - matching between gl_PerVertex blocks and gl_PerFragment blocks
- - compute shader not combined with any other stages
- give error for sharing a packed block
+ - 1.2: matching initializers for uniforms
+ - 1.5: matching between gl_PerVertex blocks and gl_PerFragment blocks
- 1.3: deprecated mixing fixed vertex/fragment stage with programmable fragment/vertex stage.
+ - 4.3: compute shader not combined with any other stages
- 4.3: remove cross-version linking restrictions.
- 4.3: Allow mismatches in interpolation and auxiliary qualification across stages.
- 4.4: A stage contains two different blocks, each with no instance name, where the blocks contain a member with the same name.
Intra-stage linking
+ - ES 3.0: location aliasing/overlap (except desktop vertex shader inputs)
+ + ES 3.0: fragment outputs all have locations, if more than one
+ exactly one main
+ Non ES: type consistency check of uniforms, globals, ins, and outs
+ Non ES: value checking of global const initializers
+ Non ES: value checking of uniform initializers
+ Non ES: location match
- - gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords
- - location aliasing/overlap (except desktop vertex shader inputs)
- - 1.0: count the number of uniforms and varyings, compare against limits
+ - Non ES: gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords
+ recursion for functions
- Non ES: block matching
- Non ES: component/binding/index/offset match check
@@ -46,8 +46,8 @@ Link Validation
Shader Functionality to Implement/Finish
ESSL 2.0 (#version 100)
- - implement non-inductive loop limitation detection
- - implement non-inductive array accesses limitation detection
+ + implement non-inductive loop limitation detection
+ + implement non-inductive array accesses limitation detection
ESSL 3.0
- "const" compile-time constant propagation in the front-end has to be complete, for all built-in functions
GLSL 1.2
@@ -72,7 +72,7 @@ Shader Functionality to Implement/Finish
- Built-in uniforms except for depth range parameters
- Built-in interface between vertex and fragment: gl_TexCoord, gl_FogFragCoord, and all the color values.
- Built-in two-sided coloring.
- - Fixed functionality for a programmable stage. Supply shaders for all stages currently being used.
+ - Fixed functionality for a programmable stage.
- ftransform(). Use invariant outputs instead.
GLSL 1.5 (Non-ES)
- Deprecated gl_MaxVaryingComponents
diff --git a/glslang.vcxproj b/glslang.vcxproj
index f54d85da..47ba6ee1 100644
--- a/glslang.vcxproj
+++ b/glslang.vcxproj
@@ -157,6 +157,7 @@ xcopy /y $(IntDir)$(TargetName)$(TargetExt) Test
+
@@ -171,7 +172,6 @@ xcopy /y $(IntDir)$(TargetName)$(TargetExt) Test
-
@@ -192,7 +192,6 @@ xcopy /y $(IntDir)$(TargetName)$(TargetExt) Test
-
diff --git a/glslang.vcxproj.filters b/glslang.vcxproj.filters
index 9f127417..62fb9ae2 100644
--- a/glslang.vcxproj.filters
+++ b/glslang.vcxproj.filters
@@ -49,9 +49,6 @@
Machine Independent
-
- Machine Independent
-
Machine Independent
@@ -112,6 +109,9 @@
Machine Independent
+
+ Machine Independent
+
@@ -120,9 +120,6 @@
Machine Independent
-
- Machine Independent
-
Machine Independent
diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp
index 0088dcde..d2179451 100644
--- a/glslang/MachineIndependent/Intermediate.cpp
+++ b/glslang/MachineIndependent/Intermediate.cpp
@@ -39,7 +39,6 @@
//
#include "localintermediate.h"
-#include "QualifierAlive.h"
#include "RemoveTree.h"
#include "SymbolTable.h"
@@ -928,275 +927,6 @@ void TIntermediate::addToCallGraph(TInfoSink& infoSink, const TString& caller, c
callGraph.push_front(TCall(caller, callee));
}
-//
-// Merge the information from 'unit' into 'this'
-//
-void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
-{
- numMains += unit.numMains;
- numErrors += unit.numErrors;
- callGraph.insert(callGraph.end(), unit.callGraph.begin(), unit.callGraph.end());
-
- if ((profile != EEsProfile && unit.profile == EEsProfile) ||
- (profile == EEsProfile && unit.profile != EEsProfile))
- error(infoSink, "Cannot mix ES profile with non-ES profile shaders\n");
-
- if (unit.treeRoot == 0)
- return;
-
- if (treeRoot == 0) {
- version = unit.version;
- treeRoot = unit.treeRoot;
- return;
- } else
- version = std::max(version, unit.version);
-
- // Get the top-level globals of each level
- TIntermSequence& globals = treeRoot->getAsAggregate()->getSequence();
- TIntermSequence& unitGlobals = unit.treeRoot->getAsAggregate()->getSequence();
-
- // Get the last members of the sequences, expected to be the linker-object lists
- assert(globals.back()->getAsAggregate()->getOp() == EOpLinkerObjects);
- assert(unitGlobals.back()->getAsAggregate()->getOp() == EOpLinkerObjects);
- TIntermSequence& linkerObjects = globals.back()->getAsAggregate()->getSequence();
- TIntermSequence& unitLinkerObjects = unitGlobals.back()->getAsAggregate()->getSequence();
-
- mergeBodies(infoSink, globals, unitGlobals);
- mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects);
-}
-
-//
-// Merge the function bodies and global-level initalizers from unitGlobals into globals.
-// Will error check duplication of function bodies for the same signature.
-//
-void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, const TIntermSequence& unitGlobals)
-{
- // TODO: Performance: Processing in alphabetical order will be faster
-
- // Error check the global objects, not including the linker objects
- for (unsigned int child = 0; child < globals.size() - 1; ++child) {
- for (unsigned int unitChild = 0; unitChild < unitGlobals.size() - 1; ++unitChild) {
- TIntermAggregate* body = globals[child]->getAsAggregate();
- TIntermAggregate* unitBody = unitGlobals[unitChild]->getAsAggregate();
- if (body && unitBody && body->getOp() == EOpFunction && unitBody->getOp() == EOpFunction && body->getName() == unitBody->getName()) {
- error(infoSink, "Multiple function bodies in multiple compilation units for the same signature in the same stage:");
- infoSink.info << " " << globals[child]->getAsAggregate()->getName() << "\n";
- }
- }
- }
-
- // Merge the global objects, just in front of the linker objects
- globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1);
-}
-
-//
-// Merge the linker objects from unitLinkerObjects into linkerObjects.
-// Duplication is expected and filtered out, but contradictions are an error.
-//
-void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects)
-{
- // Error check and merge the linker objects (duplicates should not be merged)
- std::size_t initialNumLinkerObjects = linkerObjects.size();
- for (unsigned int unitLinkObj = 0; unitLinkObj < unitLinkerObjects.size(); ++unitLinkObj) {
- bool merge = true;
- for (std::size_t linkObj = 0; linkObj < initialNumLinkerObjects; ++linkObj) {
- TIntermSymbol* symbol = linkerObjects[linkObj]->getAsSymbolNode();
- TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode();
- assert(symbol && unitSymbol);
- if (symbol->getName() == unitSymbol->getName()) {
- // filter out copy
- merge = false;
-
- // but if one has an initializer and the other does not, update
- // the initializer
- if (symbol->getConstArray().empty() && ! unitSymbol->getConstArray().empty())
- symbol->setConstArray(unitSymbol->getConstArray());
-
- // Check for consistent types/qualification/initializers etc.
- linkErrorCheck(infoSink, *symbol, *unitSymbol, false);
- }
- }
- if (merge)
- linkerObjects.push_back(unitLinkerObjects[unitLinkObj]);
- }
-}
-
-//
-// Do final link-time error checking of a complete (merged) intermediate representation.
-// (Most error checking was done during merging).
-//
-void TIntermediate::errorCheck(TInfoSink& infoSink)
-{
- if (numMains < 1)
- error(infoSink, "Missing entry point: Each stage requires one \"void main()\" entry point");
-
- checkCallGraphCycles(infoSink);
-}
-
-//
-// See if the call graph contains any static recursion, which is disallowed
-// by the specification.
-//
-void TIntermediate::checkCallGraphCycles(TInfoSink& infoSink)
-{
- // Reset everything, once.
- for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
- call->visited = false;
- call->subGraph = false;
- call->errorGiven = false;
- }
-
- //
- // Loop, looking for a new connected subgraph. One subgraph is handled per loop iteration.
- //
-
- TCall* newRoot;
- do {
- // See if we have unvisited parts of the graph.
- newRoot = 0;
- for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
- if (! call->visited) {
- newRoot = &(*call);
- break;
- }
- }
-
- // If not, we are done.
- if (! newRoot)
- break;
-
- // Otherwise, we found a new subgraph, process it:
- // See what all can be reached by this new root, and if any of
- // that is recursive. This is done by marking processed calls as active,
- // and if a new call is found that is already active, we looped,
- // thereby detecting recursion.
- std::list stack;
- stack.push_back(newRoot);
- newRoot->subGraph = true;
- while (! stack.empty()) {
- // get a caller
- TCall* call = stack.back();
- stack.pop_back();
-
- // Add to the stack all the callees of the last subgraph node popped from the stack.
- // This algorithm always terminates, because only subGraph == false causes a push
- // and all pushes change subGraph to true, and nothing changes subGraph to false.
- for (TGraph::iterator child = callGraph.begin(); child != callGraph.end(); ++child) {
- if (call->callee == child->caller) {
- if (child->subGraph) {
- if (! child->errorGiven) {
- error(infoSink, "Recursion detected:");
- infoSink.info << " " << call->callee << " calling " << child->callee << "\n";
- child->errorGiven = true;
- }
- } else {
- child->subGraph = true;
- stack.push_back(&(*child));
- }
- }
- }
- } // end while, meaning nothing left to process in this subtree
-
- // Mark all the subGraph nodes as visited, closing out this subgraph.
- for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
- if (call->subGraph)
- call->visited = true;
- }
-
- } while (newRoot); // redundant loop check; should always exit via the 'break' above
-}
-
-void TIntermediate::error(TInfoSink& infoSink, const char* message)
-{
- infoSink.info.prefix(EPrefixError);
- infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n";
-
- ++numErrors;
-}
-
-//
-// Compare two global objects from two compilation units and see if they match
-// well enough. Rules can be different for intra- vs. cross-stage matching.
-//
-// This function only does one of intra- or cross-stage matching per call.
-//
-// TODO: Linker Functionality: this function is under active development
-//
-void TIntermediate::linkErrorCheck(TInfoSink& infoSink, const TIntermSymbol& symbol, const TIntermSymbol& unitSymbol, bool crossStage)
-{
- bool writeTypeComparison = false;
-
- // Types have to match
- if (symbol.getType() != unitSymbol.getType()) {
- error(infoSink, "Types must match:");
- writeTypeComparison = true;
- }
-
- // Qualifiers have to (almost) match
-
- // Storage...
- if (symbol.getQualifier().storage != unitSymbol.getQualifier().storage) {
- error(infoSink, "Storage qualifiers must match:");
- writeTypeComparison = true;
- }
-
- // Precision...
- if (symbol.getQualifier().precision != unitSymbol.getQualifier().precision) {
- error(infoSink, "Precision qualifiers must match:");
- writeTypeComparison = true;
- }
-
- // Invariance...
- if (! crossStage && symbol.getQualifier().invariant != unitSymbol.getQualifier().invariant) {
- error(infoSink, "Presence of invariant qualifier must match:");
- writeTypeComparison = true;
- }
-
- // Auxiliary and interpolation...
- if (symbol.getQualifier().centroid != unitSymbol.getQualifier().centroid ||
- symbol.getQualifier().smooth != unitSymbol.getQualifier().smooth ||
- symbol.getQualifier().flat != unitSymbol.getQualifier().flat ||
- symbol.getQualifier().sample != unitSymbol.getQualifier().sample ||
- symbol.getQualifier().patch != unitSymbol.getQualifier().patch ||
- symbol.getQualifier().nopersp != unitSymbol.getQualifier().nopersp) {
- error(infoSink, "Interpolation and auxiliary storage qualifiers must match:");
- writeTypeComparison = true;
- }
-
- // Memory...
- if (symbol.getQualifier().shared != unitSymbol.getQualifier().shared ||
- symbol.getQualifier().coherent != unitSymbol.getQualifier().coherent ||
- symbol.getQualifier().volatil != unitSymbol.getQualifier().volatil ||
- symbol.getQualifier().restrict != unitSymbol.getQualifier().restrict ||
- symbol.getQualifier().readonly != unitSymbol.getQualifier().readonly ||
- symbol.getQualifier().writeonly != unitSymbol.getQualifier().writeonly) {
- error(infoSink, "Memory qualifiers must match:");
- writeTypeComparison = true;
- }
-
- // Layouts...
- if (symbol.getQualifier().layoutMatrix != unitSymbol.getQualifier().layoutMatrix ||
- symbol.getQualifier().layoutPacking != unitSymbol.getQualifier().layoutPacking ||
- symbol.getQualifier().layoutSlotLocation != unitSymbol.getQualifier().layoutSlotLocation) {
- error(infoSink, "Layout qualification must match:");
- writeTypeComparison = true;
- }
-
- // Initializers have to match, if both are present, and if we don't already know the types don't match
- if (! writeTypeComparison) {
- if (! symbol.getConstArray().empty() && ! unitSymbol.getConstArray().empty()) {
- if (symbol.getConstArray() != unitSymbol.getConstArray()) {
- error(infoSink, "Initializers must match:");
- infoSink.info << " " << symbol.getName() << "\n";
- }
- }
- }
-
- if (writeTypeComparison)
- infoSink.info << " " << symbol.getName() << ": \"" << symbol.getType().getCompleteString() << "\" versus \"" <<
- unitSymbol.getType().getCompleteString() << "\"\n";
-}
-
//
// This deletes the tree.
//
diff --git a/glslang/MachineIndependent/Makefile b/glslang/MachineIndependent/Makefile
index 1b6c4045..fe3b8bd8 100644
--- a/glslang/MachineIndependent/Makefile
+++ b/glslang/MachineIndependent/Makefile
@@ -9,12 +9,12 @@ LIBOSDEPENDENT=./../OSDependent/Linux/libOssource.a
LIBINITIALISATION=./../../OGLCompilersDLL/libInitializeDll.a
LIBCODEGEN=./../GenericCodeGen/libCodeGen.a
OBJECTS= Initialize.o IntermTraverse.o \
- Intermediate.o ParseHelper.o PoolAlloc.o QualifierAlive.o \
+ Intermediate.o ParseHelper.o PoolAlloc.o \
RemoveTree.o ShaderLang.o intermOut.o parseConst.o SymbolTable.o \
- InfoSink.o Versions.o Constant.o Scan.o limits.o
+ InfoSink.o Versions.o Constant.o Scan.o limits.o linkValidate.o
SRCS= gen_glslang_tab.cpp Initialize.cpp IntermTraverse.cpp \
- Intermediate.cpp ParseHelper.cpp PoolAlloc.cp QualifierAlive.cpp \
+ Intermediate.cpp ParseHelper.cpp PoolAlloc.cp \
RemoveTree.cpp ShaderLang.cpp SymbolTable.cpp intermOut.cpp \
parseConst.cpp InfoSink.cpp Versions.cpp Constant.cpp Scan.cpp
CPPFLAGS=$(DEFINE) $(INCLUDE) -fPIC
@@ -98,7 +98,7 @@ Intermediate.o: localintermediate.h ../Include/intermediate.h
Intermediate.o: ../Public/ShaderLang.h SymbolTable.h ../Include/Common.h
Intermediate.o: ../Include/intermediate.h ../Include/Types.h
Intermediate.o: ../Include/BaseTypes.h ../Include/ConstantUnion.h
-Intermediate.o: ../Include/InfoSink.h QualifierAlive.h RemoveTree.h
+Intermediate.o: ../Include/InfoSink.h RemoveTree.h
ParseHelper.o: ParseHelper.h ../Include/ShHandle.h
ParseHelper.o: ../Public/ShaderLang.h ../Include/InfoSink.h
ParseHelper.o: ../Include/Common.h ../Include/PoolAlloc.h SymbolTable.h
@@ -109,7 +109,6 @@ ParseHelper.o: localintermediate.h ../Include/intermediate.h
ParseHelper.o: ../Public/ShaderLang.h
ParseHelper.o: ../OSDependent/Linux/osinclude.h
ParseHelper.o: ../Include/InitializeGlobals.h ../Include/PoolAlloc.h
-QualifierAlive.o: ../Include/intermediate.h
Scan.o: Scan.h
Scan.o: ParseHelper.h SymbolTable.h
Scan.o: glslang_tab.cpp.h
@@ -147,3 +146,4 @@ InfoSink.o: ../Include/InfoSink.h
Versions.o: ParseHelper.h Versions.h ../Include/ShHandle.h SymbolTable.h localintermediate.h
Constant.o: localintermediate.h ../Include/intermediate.h ../Public/ShaderLang.h SymbolTable.h Versions.h
limits.o: ParseHelper.h
+linkValidate.o: localintermediate.h
diff --git a/glslang/MachineIndependent/QualifierAlive.cpp b/glslang/MachineIndependent/QualifierAlive.cpp
deleted file mode 100644
index e6c632f6..00000000
--- a/glslang/MachineIndependent/QualifierAlive.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-//
-//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
-//All rights reserved.
-//
-//Redistribution and use in source and binary forms, with or without
-//modification, are permitted provided that the following conditions
-//are met:
-//
-// Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//
-// Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-//
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-//POSSIBILITY OF SUCH DAMAGE.
-//
-
-#ifdef USE_QUALIFIER_ALIVE
-
-#include "../Include/intermediate.h"
-
-namespace glslang {
-
-class TAliveTraverser : public TIntermTraverser {
-public:
- TAliveTraverser(TStorageQualifier q) : TIntermTraverser(), found(false), qualifier(q)
- {
- visitSymbol = AliveSymbol;
- visitSelection = AliveSelection;
- rightToLeft = true;
- }
- bool wasFound() { return found; }
-protected:
- bool found;
- TStorageQualifier qualifier;
-
- friend void AliveSymbol(TIntermSymbol*, TIntermTraverser*);
- friend bool AliveSelection(bool, TIntermSelection*, TIntermTraverser*);
-};
-
-//
-// Report whether or not a variable of the given qualifier type
-// is guaranteed written. Not always possible to determine if
-// it is written conditionally.
-//
-// It does not do this well yet, this is just a place holder
-// that simply determines if it was reference at all, anywhere.
-//
-bool QualifierWritten(TIntermNode* node, TStorageQualifier qualifier)
-{
- TAliveTraverser it(qualifier);
-
- if (node)
- node->traverse(&it);
-
- return it.wasFound();
-}
-
-void AliveSymbol(TIntermSymbol* node, TIntermTraverser* it)
-{
- TAliveTraverser* lit = static_cast(it);
-
- //
- // If it's what we're looking for, record it.
- //
- if (node->getQualifier().storage == lit->qualifier)
- lit->found = true;
-}
-
-bool AliveSelection(bool preVisit, TIntermSelection* node, TIntermTraverser* it)
-{
- TAliveTraverser* lit = static_cast(it);
-
- if (lit->wasFound())
- return false;
-
- return true;
-}
-
-} // end namespace glslang
-
-#endif
diff --git a/glslang/MachineIndependent/QualifierAlive.h b/glslang/MachineIndependent/QualifierAlive.h
deleted file mode 100644
index ac172da6..00000000
--- a/glslang/MachineIndependent/QualifierAlive.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
-//All rights reserved.
-//
-//Redistribution and use in source and binary forms, with or without
-//modification, are permitted provided that the following conditions
-//are met:
-//
-// Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//
-// Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-//
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-//POSSIBILITY OF SUCH DAMAGE.
-//
-
-namespace glslang {
-
-bool QualifierWritten(TIntermNode* root, TStorageQualifier);
-
-} // end namespace glslang
diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp
index eae5a80f..fe5c5a3c 100644
--- a/glslang/MachineIndependent/ShaderLang.cpp
+++ b/glslang/MachineIndependent/ShaderLang.cpp
@@ -145,7 +145,7 @@ bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profil
if (! parseContext.parseShaderStrings(ppContext, const_cast(builtInShaders), builtInLengths, 1) != 0) {
infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
- printf("Unable to parse built-ins\n");
+ printf("Unable to parse built-ins\n%s\n", infoSink.info.c_str());
return false;
}
diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp
new file mode 100644
index 00000000..d37b078e
--- /dev/null
+++ b/glslang/MachineIndependent/linkValidate.cpp
@@ -0,0 +1,370 @@
+//
+//Copyright (C) 2013 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Do link-time merging and validation of intermediate representations.
+//
+// Basic model is that during compilation, each compilation unit (shader) is
+// compiled into one TIntermediate instance. Then, at link time, multiple
+// units for the same stage can be merged together, which can generate errors.
+// Then, after all merging, a single instance of TIntermediate represents
+// the whole stage. A final error check can be done on the resulting stage,
+// even if no merging was done (i.e., the stage was only one compilation unit).
+//
+
+#include "localintermediate.h"
+#include "../Include/InfoSink.h"
+
+namespace glslang {
+
+//
+// Link-time error emitter.
+//
+void TIntermediate::error(TInfoSink& infoSink, const char* message)
+{
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n";
+
+ ++numErrors;
+}
+
+//
+// Merge the information from 'unit' into 'this'
+//
+void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
+{
+ numMains += unit.numMains;
+ numErrors += unit.numErrors;
+ callGraph.insert(callGraph.end(), unit.callGraph.begin(), unit.callGraph.end());
+
+ if ((profile != EEsProfile && unit.profile == EEsProfile) ||
+ (profile == EEsProfile && unit.profile != EEsProfile))
+ error(infoSink, "Cannot mix ES profile with non-ES profile shaders\n");
+
+ if (unit.treeRoot == 0)
+ return;
+
+ if (treeRoot == 0) {
+ version = unit.version;
+ treeRoot = unit.treeRoot;
+ return;
+ } else
+ version = std::max(version, unit.version);
+
+ // Get the top-level globals of each unit
+ TIntermSequence& globals = treeRoot->getAsAggregate()->getSequence();
+ TIntermSequence& unitGlobals = unit.treeRoot->getAsAggregate()->getSequence();
+
+ // Get the linker-object lists
+ TIntermSequence& linkerObjects = findLinkerObjects();
+ TIntermSequence& unitLinkerObjects = unit.findLinkerObjects();
+
+ mergeBodies(infoSink, globals, unitGlobals);
+ mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects);
+}
+
+//
+// Merge the function bodies and global-level initalizers from unitGlobals into globals.
+// Will error check duplication of function bodies for the same signature.
+//
+void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, const TIntermSequence& unitGlobals)
+{
+ // TODO: Performance: Processing in alphabetical order will be faster
+
+ // Error check the global objects, not including the linker objects
+ for (unsigned int child = 0; child < globals.size() - 1; ++child) {
+ for (unsigned int unitChild = 0; unitChild < unitGlobals.size() - 1; ++unitChild) {
+ TIntermAggregate* body = globals[child]->getAsAggregate();
+ TIntermAggregate* unitBody = unitGlobals[unitChild]->getAsAggregate();
+ if (body && unitBody && body->getOp() == EOpFunction && unitBody->getOp() == EOpFunction && body->getName() == unitBody->getName()) {
+ error(infoSink, "Multiple function bodies in multiple compilation units for the same signature in the same stage:");
+ infoSink.info << " " << globals[child]->getAsAggregate()->getName() << "\n";
+ }
+ }
+ }
+
+ // Merge the global objects, just in front of the linker objects
+ globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1);
+}
+
+//
+// Merge the linker objects from unitLinkerObjects into linkerObjects.
+// Duplication is expected and filtered out, but contradictions are an error.
+//
+void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects)
+{
+ // Error check and merge the linker objects (duplicates should not be merged)
+ std::size_t initialNumLinkerObjects = linkerObjects.size();
+ for (unsigned int unitLinkObj = 0; unitLinkObj < unitLinkerObjects.size(); ++unitLinkObj) {
+ bool merge = true;
+ for (std::size_t linkObj = 0; linkObj < initialNumLinkerObjects; ++linkObj) {
+ TIntermSymbol* symbol = linkerObjects[linkObj]->getAsSymbolNode();
+ TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode();
+ assert(symbol && unitSymbol);
+ if (symbol->getName() == unitSymbol->getName()) {
+ // filter out copy
+ merge = false;
+
+ // but if one has an initializer and the other does not, update
+ // the initializer
+ if (symbol->getConstArray().empty() && ! unitSymbol->getConstArray().empty())
+ symbol->setConstArray(unitSymbol->getConstArray());
+
+ // Check for consistent types/qualification/initializers etc.
+ mergeErrorCheck(infoSink, *symbol, *unitSymbol, false);
+ }
+ }
+ if (merge)
+ linkerObjects.push_back(unitLinkerObjects[unitLinkObj]);
+ }
+}
+
+//
+// Compare two global objects from two compilation units and see if they match
+// well enough. Rules can be different for intra- vs. cross-stage matching.
+//
+// This function only does one of intra- or cross-stage matching per call.
+//
+// TODO: Linker Functionality: this function is under active development
+//
+void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& symbol, const TIntermSymbol& unitSymbol, bool crossStage)
+{
+ bool writeTypeComparison = false;
+
+ // Types have to match
+ if (symbol.getType() != unitSymbol.getType()) {
+ error(infoSink, "Types must match:");
+ writeTypeComparison = true;
+ }
+
+ // Qualifiers have to (almost) match
+
+ // Storage...
+ if (symbol.getQualifier().storage != unitSymbol.getQualifier().storage) {
+ error(infoSink, "Storage qualifiers must match:");
+ writeTypeComparison = true;
+ }
+
+ // Precision...
+ if (symbol.getQualifier().precision != unitSymbol.getQualifier().precision) {
+ error(infoSink, "Precision qualifiers must match:");
+ writeTypeComparison = true;
+ }
+
+ // Invariance...
+ if (! crossStage && symbol.getQualifier().invariant != unitSymbol.getQualifier().invariant) {
+ error(infoSink, "Presence of invariant qualifier must match:");
+ writeTypeComparison = true;
+ }
+
+ // Auxiliary and interpolation...
+ if (symbol.getQualifier().centroid != unitSymbol.getQualifier().centroid ||
+ symbol.getQualifier().smooth != unitSymbol.getQualifier().smooth ||
+ symbol.getQualifier().flat != unitSymbol.getQualifier().flat ||
+ symbol.getQualifier().sample != unitSymbol.getQualifier().sample ||
+ symbol.getQualifier().patch != unitSymbol.getQualifier().patch ||
+ symbol.getQualifier().nopersp != unitSymbol.getQualifier().nopersp) {
+ error(infoSink, "Interpolation and auxiliary storage qualifiers must match:");
+ writeTypeComparison = true;
+ }
+
+ // Memory...
+ if (symbol.getQualifier().shared != unitSymbol.getQualifier().shared ||
+ symbol.getQualifier().coherent != unitSymbol.getQualifier().coherent ||
+ symbol.getQualifier().volatil != unitSymbol.getQualifier().volatil ||
+ symbol.getQualifier().restrict != unitSymbol.getQualifier().restrict ||
+ symbol.getQualifier().readonly != unitSymbol.getQualifier().readonly ||
+ symbol.getQualifier().writeonly != unitSymbol.getQualifier().writeonly) {
+ error(infoSink, "Memory qualifiers must match:");
+ writeTypeComparison = true;
+ }
+
+ // Layouts...
+ if (symbol.getQualifier().layoutMatrix != unitSymbol.getQualifier().layoutMatrix ||
+ symbol.getQualifier().layoutPacking != unitSymbol.getQualifier().layoutPacking ||
+ symbol.getQualifier().layoutSlotLocation != unitSymbol.getQualifier().layoutSlotLocation) {
+ error(infoSink, "Layout qualification must match:");
+ writeTypeComparison = true;
+ }
+
+ // Initializers have to match, if both are present, and if we don't already know the types don't match
+ if (! writeTypeComparison) {
+ if (! symbol.getConstArray().empty() && ! unitSymbol.getConstArray().empty()) {
+ if (symbol.getConstArray() != unitSymbol.getConstArray()) {
+ error(infoSink, "Initializers must match:");
+ infoSink.info << " " << symbol.getName() << "\n";
+ }
+ }
+ }
+
+ if (writeTypeComparison)
+ infoSink.info << " " << symbol.getName() << ": \"" << symbol.getType().getCompleteString() << "\" versus \"" <<
+ unitSymbol.getType().getCompleteString() << "\"\n";
+}
+
+//
+// Do final link-time error checking of a complete (merged) intermediate representation.
+// (Much error checking was done during merging).
+//
+void TIntermediate::errorCheck(TInfoSink& infoSink)
+{
+ if (numMains < 1)
+ error(infoSink, "Missing entry point: Each stage requires one \"void main()\" entry point");
+
+ // recursion checking
+ checkCallGraphCycles(infoSink);
+
+ // overlap/alias/missing I/O, etc.
+ inOutLocationCheck(infoSink);
+}
+
+//
+// See if the call graph contains any static recursion, which is disallowed
+// by the specification.
+//
+void TIntermediate::checkCallGraphCycles(TInfoSink& infoSink)
+{
+ // Reset everything, once.
+ for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
+ call->visited = false;
+ call->subGraph = false;
+ call->errorGiven = false;
+ }
+
+ //
+ // Loop, looking for a new connected subgraph. One subgraph is handled per loop iteration.
+ //
+
+ TCall* newRoot;
+ do {
+ // See if we have unvisited parts of the graph.
+ newRoot = 0;
+ for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
+ if (! call->visited) {
+ newRoot = &(*call);
+ break;
+ }
+ }
+
+ // If not, we are done.
+ if (! newRoot)
+ break;
+
+ // Otherwise, we found a new subgraph, process it:
+ // See what all can be reached by this new root, and if any of
+ // that is recursive. This is done by marking processed calls as active,
+ // and if a new call is found that is already active, we looped,
+ // thereby detecting recursion.
+ std::list stack;
+ stack.push_back(newRoot);
+ newRoot->subGraph = true;
+ while (! stack.empty()) {
+ // get a caller
+ TCall* call = stack.back();
+ stack.pop_back();
+
+ // Add to the stack all the callees of the last subgraph node popped from the stack.
+ // This algorithm always terminates, because only subGraph == false causes a push
+ // and all pushes change subGraph to true, and nothing changes subGraph to false.
+ for (TGraph::iterator child = callGraph.begin(); child != callGraph.end(); ++child) {
+ if (call->callee == child->caller) {
+ if (child->subGraph) {
+ if (! child->errorGiven) {
+ error(infoSink, "Recursion detected:");
+ infoSink.info << " " << call->callee << " calling " << child->callee << "\n";
+ child->errorGiven = true;
+ }
+ } else {
+ child->subGraph = true;
+ stack.push_back(&(*child));
+ }
+ }
+ }
+ } // end while, meaning nothing left to process in this subtree
+
+ // Mark all the subGraph nodes as visited, closing out this subgraph.
+ for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
+ if (call->subGraph)
+ call->visited = true;
+ }
+
+ } while (newRoot); // redundant loop check; should always exit via the 'break' above
+}
+
+//
+// Satisfy rules for location qualifiers on inputs and outputs
+//
+void TIntermediate::inOutLocationCheck(TInfoSink& infoSink)
+{
+ // ES 3.0 requires all outputs to have location qualifiers if there is more than one output
+ bool fragOutHasLocation = false;
+ bool fragOutWithNoLocation = false;
+ int numFragOut = 0;
+
+ // TODO: maps for location collision checking
+
+ TIntermSequence& linkObjects = findLinkerObjects();
+ for (size_t i = 0; i < linkObjects.size(); ++i) {
+ const TType& type = linkObjects[i]->getAsTyped()->getType();
+ const TQualifier& qualifier = type.getQualifier();
+ if (language == EShLangFragment) {
+ if (qualifier.storage == EvqVaryingOut) {
+ ++numFragOut;
+ if (qualifier.hasLocation())
+ fragOutHasLocation = true;
+ else
+ fragOutWithNoLocation = true;
+ }
+ }
+ }
+
+ if (profile == EEsProfile) {
+ if (numFragOut > 1 && fragOutWithNoLocation)
+ error(infoSink, "when more than one fragment shader output, all must have location qualifiers");
+ }
+}
+
+TIntermSequence& TIntermediate::findLinkerObjects()
+{
+ // Get the top-level globals
+ TIntermSequence& globals = treeRoot->getAsAggregate()->getSequence();
+
+ // Get the last member of the sequences, expected to be the linker-object lists
+ assert(globals.back()->getAsAggregate()->getOp() == EOpLinkerObjects);
+
+ return globals.back()->getAsAggregate()->getSequence();
+}
+
+} // end namespace glslang
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index f038211a..769167e4 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -107,14 +107,16 @@ public:
void removeTree();
protected:
+ void error(TInfoSink& infoSink, const char*);
void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
- void error(TInfoSink& infoSink, const char*);
- void linkErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage);
+ void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage);
void checkCallGraphCycles(TInfoSink&);
+ void inOutLocationCheck(TInfoSink&);
+ TIntermSequence& findLinkerObjects();
protected:
- EShLanguage language;
+ const EShLanguage language;
TIntermNode* treeRoot;
EProfile profile;
int version;