diff --git a/include/asm/warning.h b/include/asm/warning.h index 9f6f0ca6..2185d0e9 100644 --- a/include/asm/warning.h +++ b/include/asm/warning.h @@ -15,6 +15,7 @@ extern unsigned int nbErrors; enum WarningID { WARNING_ASSERT, /* Assertions */ + WARNING_BACKWARDS_FOR, /* `for` loop with backwards range */ WARNING_BUILTIN_ARG, /* Invalid args to builtins */ WARNING_CHARMAP_REDEF, /* Charmap entry re-definition */ WARNING_DIV, /* Division undefined behavior */ diff --git a/src/asm/fstack.c b/src/asm/fstack.c index 8ddfb78d..c40d1a29 100644 --- a/src/asm/fstack.c +++ b/src/asm/fstack.c @@ -487,6 +487,10 @@ void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step, else if (step == 0) error("FOR cannot have a step value of 0\n"); + if ((step > 0 && start > stop) || (step < 0 && start < stop)) + warning(WARNING_BACKWARDS_FOR, "FOR goes backwards from %d to %d by %d\n", + start, stop, step); + if (count == 0) return; if (!newReptContext(reptLineNo, body, size)) diff --git a/src/asm/rgbasm.1 b/src/asm/rgbasm.1 index 801861ae..644d4d2f 100644 --- a/src/asm/rgbasm.1 +++ b/src/asm/rgbasm.1 @@ -189,7 +189,7 @@ Ignoring the prefix, entries are listed alphabetically. .Bl -tag -width Ds .It Fl Wno-assert -Warns when +Warn when .Ic WARN Ns No -type assertions fail. (See .Dq Aborting the assembly process @@ -197,6 +197,12 @@ in .Xr rgbasm 5 for .Ic ASSERT ) . +.It Fl Wbackwards-for +Warn when +.Ic FOR +loops have their start and stop values switched according to the step value. +This warning is enabled by +.Fl Wall . .It Fl Wbuiltin-args Warn about incorrect arguments to built-in functions, such as .Fn STRSUB @@ -239,7 +245,7 @@ constant or directive are encountered. .It Fl Wshift Warn when shifting right a negative value. -Use a division by 2^N instead. +Use a division by 2**N instead. .It Fl Wshift-amount Warn when a shift's operand is negative or greater than 32. .It Fl Wno-truncation diff --git a/src/asm/warning.c b/src/asm/warning.c index 10ef1f4a..40d7661a 100644 --- a/src/asm/warning.c +++ b/src/asm/warning.c @@ -30,6 +30,7 @@ enum WarningState { static enum WarningState const defaultWarnings[NB_WARNINGS] = { [WARNING_ASSERT] = WARNING_ENABLED, + [WARNING_BACKWARDS_FOR] = WARNING_DISABLED, [WARNING_BUILTIN_ARG] = WARNING_DISABLED, [WARNING_CHARMAP_REDEF] = WARNING_DISABLED, [WARNING_DIV] = WARNING_DISABLED, @@ -72,6 +73,7 @@ static enum WarningState warningState(enum WarningID id) static char const *warningFlags[NB_WARNINGS_ALL] = { "assert", + "backwards-for", "builtin-args", "charmap-redef", "div", @@ -100,6 +102,7 @@ enum MetaWarningCommand { /* Warnings that probably indicate an error */ static uint8_t const _wallCommands[] = { + WARNING_BACKWARDS_FOR, WARNING_BUILTIN_ARG, WARNING_CHARMAP_REDEF, WARNING_EMPTY_DATA_DIRECTIVE, @@ -119,6 +122,7 @@ static uint8_t const _wextraCommands[] = { /* Literally everything. Notably useful for testing */ static uint8_t const _weverythingCommands[] = { + WARNING_BACKWARDS_FOR, WARNING_BUILTIN_ARG, WARNING_DIV, WARNING_EMPTY_DATA_DIRECTIVE, diff --git a/test/asm/for.asm b/test/asm/for.asm index 65a11634..7d04d014 100644 --- a/test/asm/for.asm +++ b/test/asm/for.asm @@ -8,13 +8,17 @@ for v, 0 endr for v, 2, 1 - print "unreached" + print "backwards" endr for v, 1, 2, 0 print "unreached" endr +for v, 1, 2, -1 + print "backwards" +endr + for x, 1, 5+1 print "{d:x} " endr diff --git a/test/asm/for.err b/test/asm/for.err index f3d7f2a8..c5fd62b4 100644 --- a/test/asm/for.err +++ b/test/asm/for.err @@ -1,6 +1,10 @@ +warning: for.asm(12): [-Wbackwards-for] + FOR goes backwards from 2 to 1 by 1 ERROR: for.asm(16): FOR cannot have a step value of 0 -ERROR: for.asm(41) -> for.asm::REPT~4(47): - 'v' already defined as constant at for.asm(41) -> for.asm::REPT~4(45) -FATAL: for.asm(41) -> for.asm::REPT~4(47): +warning: for.asm(20): [-Wbackwards-for] + FOR goes backwards from 1 to 2 by -1 +ERROR: for.asm(45) -> for.asm::REPT~4(51): + 'v' already defined as constant at for.asm(45) -> for.asm::REPT~4(49) +FATAL: for.asm(45) -> for.asm::REPT~4(51): Failed to update FOR symbol value