mirror of
https://github.com/irmen/prog8.git
synced 2026-04-25 12:33:55 +00:00
add a -warnimplicitcasts compiler option
This commit is contained in:
@@ -18,6 +18,7 @@ class CompilationOptions(val output: OutputType,
|
||||
var loadAddress: UInt,
|
||||
var memtopAddress: UInt,
|
||||
var warnSymbolShadowing: Boolean = false,
|
||||
var warnImplicitTypeCast: Boolean = false,
|
||||
var optimize: Boolean = false,
|
||||
var asmQuiet: Boolean = false,
|
||||
var asmListfile: Boolean = false,
|
||||
|
||||
@@ -69,6 +69,7 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||
val varsHighBank by cli.option(ArgType.Int, fullName = "varshigh", description = "put uninitialized variables in high memory area instead of at the end of the program. On the cx16 target the value specifies the HIRAM bank to use, on other systems this value is ignored.")
|
||||
val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "run a .p8ir IR source file in the embedded VM")
|
||||
val warnSymbolShadowing by cli.option(ArgType.Boolean, fullName = "warnshadow", description="show assembler warnings about symbol shadowing")
|
||||
val warnImplicitTypeCasts by cli.option(ArgType.Boolean, fullName = "warnimplicitcasts", description="show compiler warnings about implicit casts from a smaller to a larger type")
|
||||
val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watch for file changes)")
|
||||
val version by cli.option(ArgType.Boolean, fullName = "version", description = "print compiler version and exit")
|
||||
val moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").optional().multiple(999)
|
||||
@@ -189,6 +190,7 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||
if(checkSource==true) false else dontOptimize != true,
|
||||
if(checkSource==true) false else dontWriteAssembly != true,
|
||||
warnSymbolShadowing == true,
|
||||
warnImplicitTypeCasts == true,
|
||||
quietAll == true,
|
||||
quietAll == true || quietAssembler == true,
|
||||
showTimings == true,
|
||||
@@ -274,6 +276,7 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||
if(checkSource==true) false else dontOptimize != true,
|
||||
if(checkSource==true) false else dontWriteAssembly != true,
|
||||
warnSymbolShadowing == true,
|
||||
warnImplicitTypeCasts == true,
|
||||
quietAll == true,
|
||||
quietAll == true || quietAssembler == true,
|
||||
showTimings == true,
|
||||
|
||||
@@ -43,6 +43,7 @@ class CompilerArguments(val filepath: Path,
|
||||
val optimize: Boolean,
|
||||
val writeAssembly: Boolean,
|
||||
val warnSymbolShadowing: Boolean,
|
||||
val warnImplicitTypeCasts: Boolean,
|
||||
val quietAll: Boolean,
|
||||
val quietAssembler: Boolean,
|
||||
val showTimings: Boolean,
|
||||
@@ -108,6 +109,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
||||
|
||||
with(compilationOptions) {
|
||||
warnSymbolShadowing = args.warnSymbolShadowing
|
||||
warnImplicitTypeCast = args.warnImplicitTypeCasts
|
||||
optimize = args.optimize
|
||||
asmQuiet = args.quietAssembler
|
||||
quiet = args.quietAll
|
||||
|
||||
@@ -935,14 +935,14 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
|
||||
expr.add(high)
|
||||
} else {
|
||||
val low = PtBinaryExpression("<=", DataType.BOOL, srcCheck.position)
|
||||
val lowFloat = PtTypeCast(DataType.FLOAT, range.from.position)
|
||||
val lowFloat = PtTypeCast(DataType.FLOAT, true, range.from.position)
|
||||
lowFloat.add(transformExpression(range.from))
|
||||
low.add(lowFloat)
|
||||
low.add(x1)
|
||||
expr.add(low)
|
||||
val high = PtBinaryExpression("<=", DataType.BOOL, srcCheck.position)
|
||||
high.add(x2)
|
||||
val highFLoat = PtTypeCast(DataType.FLOAT, range.to.position)
|
||||
val highFLoat = PtTypeCast(DataType.FLOAT, true, range.to.position)
|
||||
highFLoat.add(transformExpression(range.to))
|
||||
high.add(highFLoat)
|
||||
expr.add(high)
|
||||
@@ -1031,7 +1031,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
|
||||
PtString(srcString.value, srcString.encoding, srcString.position)
|
||||
|
||||
private fun transform(srcCast: TypecastExpression): PtTypeCast {
|
||||
val cast = PtTypeCast(srcCast.type, srcCast.position)
|
||||
val cast = PtTypeCast(srcCast.type, srcCast.implicit, srcCast.position)
|
||||
cast.add(transformExpression(srcCast.expression))
|
||||
require(cast.type!=cast.value.type) {
|
||||
"bogus typecast shouldn't occur at ${srcCast.position}" }
|
||||
@@ -1040,7 +1040,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
|
||||
|
||||
private fun loadAsmIncludeFile(filename: String, source: SourceCode): Result<String, NoSuchFileException> {
|
||||
return if (SourceCode.isLibraryResource(filename)) {
|
||||
return com.github.michaelbull.result.runCatching {
|
||||
com.github.michaelbull.result.runCatching {
|
||||
val physFilename = SourceCode.withoutPrefix(filename)
|
||||
ImportFileSystem.getResource("/prog8lib/$physFilename").text
|
||||
}.mapError { NoSuchFileException(File(filename)) }
|
||||
|
||||
@@ -40,7 +40,7 @@ internal fun makePushPopFunctionCalls(value: PtExpression): Pair<PtFunctionCall,
|
||||
val popFunc = if(pushFloat) "floats.pop" else if(pushWord) "sys.popw" else if(pushLong) "sys.popl" else "sys.pop"
|
||||
val pushCall = PtFunctionCall(pushFunc, true, DataType.UNDEFINED, value.position)
|
||||
if(pushTypecast!=null) {
|
||||
val typecast = PtTypeCast(pushTypecast, value.position).also {
|
||||
val typecast = PtTypeCast(pushTypecast, true, value.position).also {
|
||||
it.add(value)
|
||||
}
|
||||
pushCall.add(typecast)
|
||||
@@ -48,7 +48,7 @@ internal fun makePushPopFunctionCalls(value: PtExpression): Pair<PtFunctionCall,
|
||||
pushCall.add(value)
|
||||
}
|
||||
val popCall = if(popTypecast!=null) {
|
||||
PtTypeCast(popTypecast, value.position).also {
|
||||
PtTypeCast(popTypecast, true, value.position).also {
|
||||
val returnDt = if(pushWord) DataType.UWORD else if(pushLong) DataType.LONG else if(pushFloat) DataType.FLOAT else DataType.UBYTE
|
||||
it.add(PtFunctionCall(popFunc, false, returnDt, value.position))
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
|
||||
optimize,
|
||||
writeAssembly = true,
|
||||
warnSymbolShadowing = false,
|
||||
warnImplicitTypeCasts= false,
|
||||
quietAll = true,
|
||||
quietAssembler = true,
|
||||
showTimings = false,
|
||||
|
||||
@@ -26,6 +26,7 @@ class TestCompilerOptionSourcedirs: FunSpec({
|
||||
optimize = false,
|
||||
writeAssembly = true,
|
||||
warnSymbolShadowing = false,
|
||||
warnImplicitTypeCasts = false,
|
||||
quietAll = true,
|
||||
quietAssembler = true,
|
||||
showTimings = false,
|
||||
|
||||
@@ -27,6 +27,7 @@ internal fun compileFile(
|
||||
optimize,
|
||||
writeAssembly = writeAssembly,
|
||||
warnSymbolShadowing = false,
|
||||
warnImplicitTypeCasts = false,
|
||||
quietAll = true,
|
||||
quietAssembler = true,
|
||||
showTimings = false,
|
||||
|
||||
@@ -277,6 +277,14 @@ One or more .p8 module files
|
||||
``-vm``
|
||||
load and run a 'p8ir' intermediate representation file in the internal VirtualMachine instead of compiling a prog8 program file.
|
||||
|
||||
``-warnimplicitcasts``
|
||||
Give warnings for lines where a silent (implicit) type cast is done from a smaller to a larger type.
|
||||
Example: when a byte is assigned to a word variable.
|
||||
This may indicate a potential value evaluation issue because unlike most other programming languages, Prog8 doesn't do automatic type enlargement for expressions.
|
||||
This means that for example if a=50 and b=20, a times b is *not* equal to 1000 if a and b are bytes. Only if one or both of them are explicitly casted to a word type,
|
||||
the calculation will result in the word value 1000. If you have code like this: `uword result = a * b` the compiler silently converted the *byte* result to a *word* variable,
|
||||
but maybe you expected the result to actually be 1000 here (and forgot to add a cast in the expression to make it words)
|
||||
|
||||
``-warnshadow``
|
||||
Tells the assembler to issue warning messages about symbol shadowing.
|
||||
These *can* be problematic, but usually aren't because prog8 has different scoping rules
|
||||
|
||||
@@ -10,7 +10,6 @@ Weird Heisenbug
|
||||
|
||||
Future Things and Ideas
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- add a -warnimplicitcasts and -warnexplicitcasts?
|
||||
- make builtin functions capable of returning multiple values, then make divmod() return the 2 results rather than accepting 2 extra variables as arguments
|
||||
- then also introduce lmh(longvalue) -or whatever sensible name- builtin function that returns the low, mid, hi (bank) bytes of a long.
|
||||
- add a -profile option (for now X16 only) that instruments the start (and returns?) -of every prog8 subroutine with code that dumps to the X16 emulator debug console: name of sub, stack pointer (for call depth!), emudbg cycle count. Save/restore all used registers! Start of program must set cycle count to zero.
|
||||
|
||||
@@ -424,12 +424,12 @@ class PtString(val value: String, val encoding: Encoding, position: Position) :
|
||||
}
|
||||
|
||||
|
||||
class PtTypeCast(type: DataType, position: Position) : PtExpression(type, position) {
|
||||
class PtTypeCast(type: DataType, val implicit: Boolean, position: Position) : PtExpression(type, position) {
|
||||
val value: PtExpression
|
||||
get() = children.single() as PtExpression
|
||||
|
||||
fun copy(): PtTypeCast {
|
||||
val copy = PtTypeCast(type, position)
|
||||
val copy = PtTypeCast(type, implicit, position)
|
||||
if(children[0] is PtIdentifier) {
|
||||
copy.add((children[0] as PtIdentifier).copy())
|
||||
} else {
|
||||
|
||||
@@ -19,5 +19,21 @@ fun verifyFinalAstBeforeAsmGen(program: PtProgram, options: CompilationOptions,
|
||||
errors.err("no support for using struct instances in expressions in this way yet (use pointer to struct instead)", node.position)
|
||||
}
|
||||
}
|
||||
|
||||
if(options.warnImplicitTypeCast) {
|
||||
if (node is PtTypeCast) {
|
||||
if (node.type.largerSizeThan(node.value.type)) {
|
||||
if (node.implicit) {
|
||||
errors.warn("implicit type cast to larger type: ${node.value.type} to ${node.type}", node.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (node is PtAssignment) {
|
||||
val targetDt = (node.children.first() as PtAssignTarget).type
|
||||
if (targetDt.largerSizeThan(node.value.type)) {
|
||||
errors.warn("assignment to larger type: ${node.value.type} to $targetDt", node.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user