mirror of
https://github.com/irmen/prog8.git
synced 2024-09-08 10:55:08 +00:00
improved warnings about unreachable code
This commit is contained in:
parent
edfd9d55ba
commit
c144d4e501
@ -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.")
|
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) {
|
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? {
|
private fun checkFunctionOrLabelExists(target: IdentifierReference, statement: Statement): Statement? {
|
||||||
val targetStatement = target.targetStatement(program.namespace)
|
val targetStatement = target.targetStatement(program.namespace)
|
||||||
if(targetStatement is Label || targetStatement is Subroutine || targetStatement is BuiltinFunctionStatementPlaceholder)
|
if(targetStatement is Label || targetStatement is Subroutine || targetStatement is BuiltinFunctionStatementPlaceholder)
|
||||||
|
@ -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() {
|
class Break(override val position: Position) : Statement() {
|
||||||
override lateinit var parent: Node
|
override lateinit var parent: Node
|
||||||
|
|
||||||
|
@ -169,9 +169,10 @@ private fun optimizeAst(programAst: Program, errors: ErrorReporter) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
val remover = UnusedCodeRemover()
|
val remover = UnusedCodeRemover(errors)
|
||||||
remover.visit(programAst)
|
remover.visit(programAst)
|
||||||
remover.applyModifications()
|
remover.applyModifications()
|
||||||
|
errors.handle()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun postprocessAst(programAst: Program, errors: ErrorReporter, compilerOptions: CompilationOptions) {
|
private fun postprocessAst(programAst: Program, errors: ErrorReporter, compilerOptions: CompilationOptions) {
|
||||||
|
@ -636,7 +636,11 @@ internal class AsmGen(private val program: Program,
|
|||||||
is BranchStatement -> translate(stmt)
|
is BranchStatement -> translate(stmt)
|
||||||
is IfStatement -> translate(stmt)
|
is IfStatement -> translate(stmt)
|
||||||
is ForLoop -> forloopsAsmGen.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 WhileLoop -> translate(stmt)
|
||||||
is RepeatLoop -> translate(stmt)
|
is RepeatLoop -> translate(stmt)
|
||||||
is UntilLoop -> translate(stmt)
|
is UntilLoop -> translate(stmt)
|
||||||
|
@ -136,7 +136,7 @@ internal class StatementOptimizer(private val program: Program,
|
|||||||
val subroutine = functionCallStatement.target.targetSubroutine(program.namespace)
|
val subroutine = functionCallStatement.target.targetSubroutine(program.namespace)
|
||||||
if(subroutine!=null) {
|
if(subroutine!=null) {
|
||||||
val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull()
|
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))
|
return listOf(IAstModification.Remove(functionCallStatement, parent))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
package prog8.optimizer
|
package prog8.optimizer
|
||||||
|
|
||||||
|
import prog8.ast.INameScope
|
||||||
import prog8.ast.Node
|
import prog8.ast.Node
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
|
import prog8.ast.base.ErrorReporter
|
||||||
import prog8.ast.processing.AstWalker
|
import prog8.ast.processing.AstWalker
|
||||||
import prog8.ast.processing.IAstModification
|
import prog8.ast.processing.IAstModification
|
||||||
import prog8.ast.statements.Block
|
import prog8.ast.statements.*
|
||||||
|
|
||||||
/*
|
internal class UnusedCodeRemover(private val errors: ErrorReporter): AstWalker() {
|
||||||
TODO: remove unreachable code after return and exit()
|
|
||||||
*/
|
|
||||||
|
|
||||||
internal class UnusedCodeRemover: AstWalker() {
|
|
||||||
|
|
||||||
override fun before(program: Program, parent: Node): Iterable<IAstModification> {
|
override fun before(program: Program, parent: Node): Iterable<IAstModification> {
|
||||||
val callgraph = CallGraph(program)
|
val callgraph = CallGraph(program)
|
||||||
@ -38,4 +36,33 @@ internal class UnusedCodeRemover: AstWalker() {
|
|||||||
|
|
||||||
return removals
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,53 +7,21 @@ main {
|
|||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
struct Color {
|
c64scr.print_ub(5)
|
||||||
ubyte red
|
c64.CHROUT('\n')
|
||||||
uword green
|
return
|
||||||
float blue
|
|
||||||
}
|
|
||||||
|
|
||||||
Color c = [11,22222,3.1234]
|
c64scr.print_ub(5)
|
||||||
|
|
||||||
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')
|
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
c64scr.print_ub(c.red)
|
goto start
|
||||||
c64.CHROUT('\n')
|
|
||||||
c64scr.print_uw(c.green)
|
c64scr.print_ub(5)
|
||||||
c64.CHROUT('\n')
|
|
||||||
c64flt.print_f(c.blue)
|
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
ubyte size = sizeof(Color)
|
exit(11)
|
||||||
c64scr.print_ub(size)
|
|
||||||
c64.CHROUT('\n')
|
c64scr.print_ub(5)
|
||||||
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))
|
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user