IdentifierValidator().apply(stage);
ReferenceValidator().apply(stage);
ExpressionValidator().apply(stage);
+ FlowControlValidator().apply(stage);
StageInterfaceValidator().apply(stage);
}
}
+FlowControlValidator::FlowControlValidator():
+ reachable(true)
+{ }
+
+void FlowControlValidator::visit(Block &block)
+{
+ for(NodeList<Statement>::const_iterator i=block.body.begin(); i!=block.body.end(); ++i)
+ {
+ if(!reachable)
+ {
+ diagnose(**i, Diagnostic::WARN, "Unreachable code detected");
+ break;
+ }
+ (*i)->visit(*this);
+ }
+}
+
+void FlowControlValidator::visit(FunctionDeclaration &func)
+{
+ func.body.visit(*this);
+
+ if(func.definition==&func && func.return_type_declaration)
+ {
+ const BasicTypeDeclaration *basic_ret = dynamic_cast<const BasicTypeDeclaration *>(func.return_type_declaration);
+ if(reachable && (!basic_ret || basic_ret->kind!=BasicTypeDeclaration::VOID))
+ error(func, "Missing return statement at the end of a function not returning 'void'");
+ }
+ reachable = true;
+}
+
+void FlowControlValidator::visit(Conditional &cond)
+{
+ cond.body.visit(*this);
+ bool reachable_if_true = reachable;
+ reachable = true;
+ cond.else_body.visit(*this);
+ reachable |= reachable_if_true;
+}
+
+void FlowControlValidator::visit(Iteration &iter)
+{
+ iter.body.visit(*this);
+ reachable = true;
+}
+
+
int StageInterfaceValidator::get_location(const Layout &layout)
{
for(vector<Layout::Qualifier>::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i)
virtual void visit(Return &);
};
+/** Verifies flow control constructs. Functions returning non-void must have
+return statements. Warnings are given about dead code. */
+class FlowControlValidator: private Validator
+{
+private:
+ bool reachable;
+
+public:
+ FlowControlValidator();
+
+ void apply(Stage &s) { stage = &s; s.content.visit(*this); }
+
+private:
+ virtual void visit(Block &);
+ virtual void visit(FunctionDeclaration &);
+ virtual void visit(Conditional &);
+ virtual void visit(Iteration &);
+ virtual void visit(Return &) { reachable = false; }
+ virtual void visit(Jump &) { reachable = false; }
+};
+
/** Verifies that stage input and output interfaces are valid. Linked
variables must have matching types and locations and there must not be any
overlap in locations. */
gl_Position = position;
}
+/* Expected diagnostic:
+<test>:9: Unreachable code detected
+*/
+
/* Expected output: vertex
layout(location=0) uniform mat4 mvp;
layout(location=0) in vec4 position;
{
return 1.0;
}
-int main()
+void main()
{
gl_Position = position*get_scale();
}
/* Expected output: vertex
layout(location=0) in vec4 position;
-int main()
+void main()
{
gl_Position = position*2.0;
}
#pragma MSP stage(vertex)
layout(location=0) in vec4 position;
layout(location=1) in float scale;
-int main()
+void main()
{
gl_Position = position[scale];
gl_Position = scale[position];
#pragma MSP stage(vertex)
layout(location=0) in vec4 position;
-int main()
+void main()
{
gl_Position = mat4(mvp)*vec4(position);
}
/* Expected output: vertex
layout(location=0) uniform mat4 mvp;
layout(location=0) in vec4 position;
-int main()
+void main()
{
gl_Position = mat4(mvp)*vec4(position);
}
#pragma MSP stage(vertex)
layout(location=0) in vec4 position;
-int main()
+void main()
{
vec4 c0 = mvp[0]*position;
vec4 c1 = mvp[1]*position;
/* Expected output: vertex
layout(location=0) uniform mat4 mvp;
layout(location=0) in vec4 position;
-int main()
+void main()
{
vec4 c0 = mvp[0]*position;
vec4 c1 = mvp[1]*position;