Move VerifyStaticTests from Compiler to Analysis.
This doesn't rely on anything Compiler-specific, and can just be a plain Analysis pass. Change-Id: I8564ae2a750c6daa6c449e6fa56355cc047f7010 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/444496 Auto-Submit: John Stiles <johnstiles@google.com> Commit-Queue: Ethan Nicholas <ethannicholas@google.com> Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
parent
d2f53f9e3e
commit
0fc6bedf5a
@ -1251,6 +1251,57 @@ bool Analysis::CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl,
|
||||
return !visitor.fFoundReturn;
|
||||
}
|
||||
|
||||
void Analysis::VerifyStaticTests(const Program& program) {
|
||||
class StaticTestVerifier : public ProgramVisitor {
|
||||
public:
|
||||
StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
|
||||
|
||||
using ProgramVisitor::visitProgramElement;
|
||||
|
||||
bool visitStatement(const Statement& stmt) override {
|
||||
switch (stmt.kind()) {
|
||||
case Statement::Kind::kIf:
|
||||
if (stmt.as<IfStatement>().isStatic()) {
|
||||
fReporter->error(stmt.fOffset, "static if has non-static test");
|
||||
}
|
||||
break;
|
||||
|
||||
case Statement::Kind::kSwitch:
|
||||
if (stmt.as<SwitchStatement>().isStatic()) {
|
||||
fReporter->error(stmt.fOffset, "static switch has non-static test");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return INHERITED::visitStatement(stmt);
|
||||
}
|
||||
|
||||
bool visitExpression(const Expression&) override {
|
||||
// We aren't looking for anything inside an Expression, so skip them entirely.
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
using INHERITED = ProgramVisitor;
|
||||
ErrorReporter* fReporter;
|
||||
};
|
||||
|
||||
// If invalid static tests are permitted, we don't need to check anything.
|
||||
if (program.fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
|
||||
StaticTestVerifier visitor{program.fContext->fErrors};
|
||||
for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
|
||||
if (element->is<FunctionDefinition>()) {
|
||||
visitor.visitProgramElement(*element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ProgramVisitor
|
||||
|
||||
|
@ -150,6 +150,10 @@ struct Analysis {
|
||||
// Detects functions that fail to return a value on at least one path.
|
||||
static bool CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl,
|
||||
const Statement& body);
|
||||
|
||||
// Reports leftover @if and @switch statements in a program as errors. These should have been
|
||||
// optimized away during compilation, as their tests should be constant-evaluatable.
|
||||
static void VerifyStaticTests(const Program& program);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -489,57 +489,6 @@ std::unique_ptr<Program> Compiler::convertProgram(
|
||||
#endif // SKSL_DSL_PARSER
|
||||
}
|
||||
|
||||
void Compiler::verifyStaticTests(const Program& program) {
|
||||
class StaticTestVerifier : public ProgramVisitor {
|
||||
public:
|
||||
StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
|
||||
|
||||
using ProgramVisitor::visitProgramElement;
|
||||
|
||||
bool visitStatement(const Statement& stmt) override {
|
||||
switch (stmt.kind()) {
|
||||
case Statement::Kind::kIf:
|
||||
if (stmt.as<IfStatement>().isStatic()) {
|
||||
fReporter->error(stmt.fOffset, "static if has non-static test");
|
||||
}
|
||||
break;
|
||||
|
||||
case Statement::Kind::kSwitch:
|
||||
if (stmt.as<SwitchStatement>().isStatic()) {
|
||||
fReporter->error(stmt.fOffset, "static switch has non-static test");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return INHERITED::visitStatement(stmt);
|
||||
}
|
||||
|
||||
bool visitExpression(const Expression&) override {
|
||||
// We aren't looking for anything inside an Expression, so skip them entirely.
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
using INHERITED = ProgramVisitor;
|
||||
ErrorReporter* fReporter;
|
||||
};
|
||||
|
||||
// If invalid static tests are permitted, we don't need to check anything.
|
||||
if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
|
||||
StaticTestVerifier visitor{&this->errorReporter()};
|
||||
for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
|
||||
if (element->is<FunctionDefinition>()) {
|
||||
visitor.visitProgramElement(*element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Compiler::optimize(LoadedModule& module) {
|
||||
SkASSERT(!this->errorCount());
|
||||
|
||||
@ -856,7 +805,7 @@ bool Compiler::optimize(Program& program) {
|
||||
}
|
||||
|
||||
if (this->errorCount() == 0) {
|
||||
this->verifyStaticTests(program);
|
||||
Analysis::VerifyStaticTests(program);
|
||||
}
|
||||
|
||||
return this->errorCount() == 0;
|
||||
|
@ -225,9 +225,6 @@ private:
|
||||
std::shared_ptr<SymbolTable> makeRootSymbolTable();
|
||||
std::shared_ptr<SymbolTable> makePrivateSymbolTable(std::shared_ptr<SymbolTable> parent);
|
||||
|
||||
/** Verifies that @if and @switch statements were actually optimized away. */
|
||||
void verifyStaticTests(const Program& program);
|
||||
|
||||
/** Optimize every function in the program. */
|
||||
bool optimize(Program& program);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user