improved warnings about unreachable code

This commit is contained in:
Irmen de Jong 2020-08-20 14:28:17 +02:00
parent edfd9d55ba
commit c144d4e501
7 changed files with 51 additions and 86 deletions

View File

@ -309,8 +309,6 @@ internal class AstChecker(private val program: Program,
err("Pass-by-reference types (str, array) cannot occur as a parameter type directly. Instead, use an uword to receive their address, or access the variable from the outer scope directly.")
}
}
visitStatements(subroutine.statements)
}
override fun visit(untilLoop: UntilLoop) {
@ -1027,30 +1025,6 @@ internal class AstChecker(private val program: Program,
}
}
override fun visit(scope: AnonymousScope) {
visitStatements(scope.statements)
}
private fun visitStatements(statements: List<Statement>) {
for((index, stmt) in statements.withIndex()) {
if(index < statements.lastIndex && statements[index+1] !is Subroutine) {
when {
stmt is FunctionCallStatement && stmt.target.nameInSource.last() == "exit" -> {
errors.warn("unreachable code, preceding exit call will never return", statements[index + 1].position)
}
stmt is Return && statements[index + 1] !is Subroutine -> {
errors.warn("unreachable code, preceding return statement", statements[index + 1].position)
}
stmt is Jump && statements[index + 1] !is Subroutine -> {
errors.warn("unreachable code, preceding jump statement", statements[index + 1].position)
}
}
}
stmt.accept(this)
}
}
private fun checkFunctionOrLabelExists(target: IdentifierReference, statement: Statement): Statement? {
val targetStatement = target.targetStatement(program.namespace)
if(targetStatement is Label || targetStatement is Subroutine || targetStatement is BuiltinFunctionStatementPlaceholder)

View File

@ -139,15 +139,6 @@ open class Return(var value: Expression?, override val position: Position) : Sta
}
}
class ReturnFromIrq(override val position: Position) : Return(null, position) {
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun toString(): String {
return "ReturnFromIrq(pos=$position)"
}
override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here")
}
class Break(override val position: Position) : Statement() {
override lateinit var parent: Node

View File

@ -169,9 +169,10 @@ private fun optimizeAst(programAst: Program, errors: ErrorReporter) {
break
}
val remover = UnusedCodeRemover()
val remover = UnusedCodeRemover(errors)
remover.visit(programAst)
remover.applyModifications()
errors.handle()
}
private fun postprocessAst(programAst: Program, errors: ErrorReporter, compilerOptions: CompilationOptions) {

View File

@ -636,7 +636,11 @@ internal class AsmGen(private val program: Program,
is BranchStatement -> translate(stmt)
is IfStatement -> translate(stmt)
is ForLoop -> forloopsAsmGen.translate(stmt)
is Break -> out(" jmp ${loopEndLabels.peek()}")
is Break -> {
if(loopEndLabels.isEmpty())
throw AssemblyError("break statement out of context ${stmt.position}")
out(" jmp ${loopEndLabels.peek()}")
}
is WhileLoop -> translate(stmt)
is RepeatLoop -> translate(stmt)
is UntilLoop -> translate(stmt)

View File

@ -136,7 +136,7 @@ internal class StatementOptimizer(private val program: Program,
val subroutine = functionCallStatement.target.targetSubroutine(program.namespace)
if(subroutine!=null) {
val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull()
if(first is ReturnFromIrq || first is Return)
if(first is Return)
return listOf(IAstModification.Remove(functionCallStatement, parent))
}

View File

@ -1,16 +1,14 @@
package prog8.optimizer
import prog8.ast.INameScope
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.ErrorReporter
import prog8.ast.processing.AstWalker
import prog8.ast.processing.IAstModification
import prog8.ast.statements.Block
import prog8.ast.statements.*
/*
TODO: remove unreachable code after return and exit()
*/
internal class UnusedCodeRemover: AstWalker() {
internal class UnusedCodeRemover(private val errors: ErrorReporter): AstWalker() {
override fun before(program: Program, parent: Node): Iterable<IAstModification> {
val callgraph = CallGraph(program)
@ -38,4 +36,33 @@ internal class UnusedCodeRemover: AstWalker() {
return removals
}
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
reportUnreachable(breakStmt, parent as INameScope)
return emptyList()
}
override fun before(jump: Jump, parent: Node): Iterable<IAstModification> {
reportUnreachable(jump, parent as INameScope)
return emptyList()
}
override fun before(returnStmt: Return, parent: Node): Iterable<IAstModification> {
reportUnreachable(returnStmt, parent as INameScope)
return emptyList()
}
override fun before(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
if(functionCallStatement.target.nameInSource.last() == "exit")
reportUnreachable(functionCallStatement, parent as INameScope)
return emptyList()
}
private fun reportUnreachable(stmt: Statement, parent: INameScope) {
when(val next = parent.nextSibling(stmt)) {
null, is Label, is Directive, is VarDecl, is InlineAssembly, is Subroutine, is StructDecl -> {}
else -> errors.warn("unreachable code", next.position)
}
}
}

View File

@ -7,53 +7,21 @@ main {
sub start() {
struct Color {
ubyte red
uword green
float blue
}
c64scr.print_ub(5)
c64.CHROUT('\n')
return
Color c = [11,22222,3.1234]
str string = "irmen"
byte[] ab = [1,2,3]
ubyte[] aub = [1,2,3]
word[] aw = [11,22,33]
uword[] auw = [11,22,33]
float[] af = [1.1,2.2,3.3]
c64scr.print_ub(sizeof(ab))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(aub))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(aw))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(auw))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(af))
c64.CHROUT('\n')
c64.CHROUT('\n')
c64scr.print_ub(5)
c64.CHROUT('\n')
c64scr.print_ub(c.red)
c64.CHROUT('\n')
c64scr.print_uw(c.green)
c64.CHROUT('\n')
c64flt.print_f(c.blue)
goto start
c64scr.print_ub(5)
c64.CHROUT('\n')
ubyte size = sizeof(Color)
c64scr.print_ub(size)
c64.CHROUT('\n')
c64scr.print_ub(sizeof(Color))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(c))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(c.red))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(c.green))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(c.blue))
exit(11)
c64scr.print_ub(5)
c64.CHROUT('\n')
}
}