mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Implement warning diagnostic flags for RGBLINK (#1754)
This commit is contained in:
@@ -21,6 +21,7 @@ _rgblink_completions() {
|
||||
[O]="overlay:glob-*.gb *.gbc *.sgb"
|
||||
[o]="output:glob-*.gb *.gbc *.sgb"
|
||||
[p]="pad:unk"
|
||||
[W]="warning:warning"
|
||||
)
|
||||
# Parse command-line up to current word
|
||||
local opt_ena=true
|
||||
@@ -136,6 +137,18 @@ _rgblink_completions() {
|
||||
case "$state" in
|
||||
unk) # Return with no replies: no idea what to complete!
|
||||
;;
|
||||
warning)
|
||||
mapfile -t COMPREPLY < <(compgen -W "
|
||||
assert
|
||||
div
|
||||
obsolete
|
||||
shift
|
||||
shift-amount
|
||||
truncation
|
||||
all
|
||||
everything
|
||||
error" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}")
|
||||
;;
|
||||
normal) # Acts like a glob...
|
||||
state="glob-*.o *.obj"
|
||||
;&
|
||||
|
||||
@@ -23,7 +23,7 @@ _rgbasm_warnings() {
|
||||
'obsolete:Warn when using deprecated features'
|
||||
'purge:Warn when purging exported symbols or labels'
|
||||
'shift:Warn when shifting negative values'
|
||||
'shift-amount:Warn when a shift'\''s operand it negative or \> 32'
|
||||
'shift-amount:Warn when a shift'\''s operand is negative or \> 32'
|
||||
'truncation:Warn when implicit truncation loses bits'
|
||||
'unmapped-char:Warn on unmapped character'
|
||||
'unmatched-directive:Warn on unmatched directive pair'
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
#compdef rgblink
|
||||
|
||||
_rgblink_warnings() {
|
||||
local warnings=(
|
||||
'error:Turn all warnings into errors'
|
||||
|
||||
'all:Enable most warning messages'
|
||||
'everything:Enable literally everything'
|
||||
|
||||
'assert:Warn when WARN-type asserts fail'
|
||||
'div:Warn when dividing the smallest int by -1'
|
||||
'obsolete:Warn when using deprecated features'
|
||||
'shift:Warn when shifting negative values'
|
||||
'shift-amount:Warn when a shift'\''s operand is negative or \> 32'
|
||||
'truncation:Warn when implicit truncation loses bits'
|
||||
)
|
||||
_describe warning warnings
|
||||
}
|
||||
|
||||
local args=(
|
||||
# Arguments are listed here in the same order as in the manual, except for the version and help
|
||||
'(- : * options)'{-V,--version}'[Print version number and exit]'
|
||||
@@ -19,6 +36,7 @@ local args=(
|
||||
'(-o --output)'{-o,--output}"+[Write ROM image to this file]:rom file:_files -g '*.{gb,sgb,gbc}'"
|
||||
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
|
||||
'(-S --scramble)'{-s,--scramble}'+[Activate scrambling]:scramble spec'
|
||||
'(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgblink_warnings'
|
||||
|
||||
'*'":object files:_files -g '*.o'"
|
||||
)
|
||||
|
||||
@@ -5,12 +5,37 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "diagnostics.hpp"
|
||||
|
||||
#define warningAt(where, ...) warning(where.src, where.lineNo, __VA_ARGS__)
|
||||
#define errorAt(where, ...) error(where.src, where.lineNo, __VA_ARGS__)
|
||||
#define fatalAt(where, ...) fatal(where.src, where.lineNo, __VA_ARGS__)
|
||||
|
||||
enum WarningLevel {
|
||||
LEVEL_DEFAULT, // Warnings that are enabled by default
|
||||
LEVEL_ALL, // Warnings that probably indicate an error
|
||||
LEVEL_EVERYTHING, // Literally every warning
|
||||
};
|
||||
|
||||
enum WarningID {
|
||||
WARNING_ASSERT, // Assertions
|
||||
WARNING_DIV, // Undefined division behavior
|
||||
WARNING_OBSOLETE, // Obsolete/deprecated things
|
||||
WARNING_SHIFT, // Undefined `SHIFT` behavior
|
||||
WARNING_SHIFT_AMOUNT, // Strange `SHIFT` amount
|
||||
WARNING_TRUNCATION, // Implicit truncation loses some bits
|
||||
|
||||
NB_PLAIN_WARNINGS,
|
||||
|
||||
NB_WARNINGS = NB_PLAIN_WARNINGS,
|
||||
};
|
||||
|
||||
extern Diagnostics<WarningLevel, WarningID> warnings;
|
||||
|
||||
struct FileStackNode;
|
||||
|
||||
[[gnu::format(printf, 4, 5)]]
|
||||
void warning(FileStackNode const *src, uint32_t lineNo, WarningID id, char const *fmt, ...);
|
||||
[[gnu::format(printf, 3, 4)]]
|
||||
void warning(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...);
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
|
||||
@@ -350,11 +350,7 @@ Block comments cannot be nested, so the first
|
||||
.Ql */
|
||||
will end the whole comment.
|
||||
.It Fl Wno-obsolete
|
||||
Warn when obsolete constructs such as the
|
||||
.Ic _PI
|
||||
constant or
|
||||
.Ic PRINTT
|
||||
directive are encountered.
|
||||
Warn when obsolete features are encountered, which have been deprecated and may later be removed.
|
||||
.It Fl Wnumeric-string=
|
||||
Warn when a multi-character string is treated as a number.
|
||||
.Fl Wnumeric-string=0
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
.Op Fl o Ar out_file
|
||||
.Op Fl p Ar pad_value
|
||||
.Op Fl S Ar spec
|
||||
.Op Fl W Ar warning
|
||||
.Ar
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
@@ -114,6 +115,15 @@ Useful for ROMs that fit in 32 KiB.
|
||||
Print the version of the program and exit.
|
||||
.It Fl v , Fl \-verbose
|
||||
Verbose: enable printing more information to standard error.
|
||||
.It Fl W Ar warning , Fl \-warning Ar warning
|
||||
Set warning flag
|
||||
.Ar warning .
|
||||
A warning message will be printed if
|
||||
.Ar warning
|
||||
is an unknown warning flag.
|
||||
See the
|
||||
.Sx DIAGNOSTICS
|
||||
section for a list of warnings.
|
||||
.It Fl w , Fl \-wramx
|
||||
Expand the WRAM0 section size from 4 KiB to the full 8 KiB assigned to WRAM.
|
||||
WRAMX sections that are fixed to a bank other than 1 become errors, other WRAMX sections are treated as WRAM0.
|
||||
@@ -176,6 +186,84 @@ as
|
||||
.Ic WRAMX
|
||||
sections will be treated as
|
||||
.Ic WRAM0 .
|
||||
.Sh DIAGNOSTICS
|
||||
Warnings are diagnostic messages that indicate possibly erroneous behavior that does not necessarily compromise the linking process.
|
||||
The following options alter the way warnings are processed.
|
||||
.Bl -tag -width Ds
|
||||
.It Fl Werror
|
||||
Make all warnings into errors.
|
||||
This can be negated as
|
||||
.Fl Wno-error
|
||||
to prevent turning all warnings into errors.
|
||||
.It Fl Werror=
|
||||
Make the specified warning or meta warning into an error.
|
||||
A warning's name is appended
|
||||
.Pq example: Fl Werror=assert ,
|
||||
and this warning is implicitly enabled and turned into an error.
|
||||
This can be negated as
|
||||
.Fl Wno-error=
|
||||
to prevent turning a specified warning into an error, even if
|
||||
.Fl Werror
|
||||
is in effect.
|
||||
.El
|
||||
.Pp
|
||||
The following warnings are
|
||||
.Dq meta
|
||||
warnings, that enable a collection of other warnings.
|
||||
If a specific warning is toggled via a meta flag and a specific one, the more specific one takes priority.
|
||||
The position on the command-line acts as a tie breaker, the last one taking effect.
|
||||
.Bl -tag -width Ds
|
||||
.It Fl Wall
|
||||
This enables warnings that are likely to indicate an error or undesired behavior, and that can easily be fixed.
|
||||
.It Fl Weverything
|
||||
Enables literally every warning.
|
||||
.El
|
||||
.Pp
|
||||
The following warnings are actual warning flags; with each description, the corresponding warning flag is included.
|
||||
Note that each of these flag also has a negation (for example,
|
||||
.Fl Wobsolete
|
||||
enables the warning that
|
||||
.Fl Wno-obsolete
|
||||
disables; and
|
||||
.Fl Wall
|
||||
enables every warning that
|
||||
.Fl Wno-all
|
||||
disables).
|
||||
Only the non-default flag is listed here.
|
||||
Ignoring the
|
||||
.Dq no-
|
||||
prefix, entries are listed alphabetically.
|
||||
.Bl -tag -width Ds
|
||||
.It Fl Wno-assert
|
||||
Warn when
|
||||
.Ic WARN Ns No -type
|
||||
assertions fail. (See
|
||||
.Dq Aborting the assembly process
|
||||
in
|
||||
.Xr rgbasm 5
|
||||
for
|
||||
.Ic ASSERT ) .
|
||||
.It Fl Wdiv
|
||||
Warn when dividing the smallest negative integer (-2**31) by -1, which yields itself due to integer overflow.
|
||||
This warning is enabled by
|
||||
.Fl Wall .
|
||||
.It Fl Wno-obsolete
|
||||
Warn when obsolete features are encountered, which have been deprecated and may later be removed.
|
||||
.It Fl Wshift
|
||||
Warn when shifting right a negative value.
|
||||
Use a division by 2**N instead.
|
||||
This warning is enabled by
|
||||
.Fl Wall .
|
||||
.It Fl Wshift-amount
|
||||
Warn when a shift's operand is negative or greater than 32.
|
||||
This warning is enabled by
|
||||
.Fl Wall .
|
||||
.It Fl Wno-truncation
|
||||
Warn when an implicit truncation (for example,
|
||||
.Ic db
|
||||
to an 8-bit value) loses some bits.
|
||||
This occurs when an N-bit value is 2**N or greater, or less than -2**N.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
All you need for a basic ROM is an object file, which can be made into a ROM image like so:
|
||||
.Pp
|
||||
|
||||
@@ -69,7 +69,7 @@ std::string const &FileStackNode::dump(uint32_t curLineNo) const {
|
||||
}
|
||||
|
||||
// Short options
|
||||
static char const *optstring = "dhl:m:Mn:O:o:p:S:tVvwx";
|
||||
static char const *optstring = "dhl:m:Mn:O:o:p:S:tVvW:wx";
|
||||
|
||||
// Equivalent long options
|
||||
// Please keep in the same order as short opts.
|
||||
@@ -92,6 +92,7 @@ static option const longopts[] = {
|
||||
{"tiny", no_argument, nullptr, 't'},
|
||||
{"version", no_argument, nullptr, 'V'},
|
||||
{"verbose", no_argument, nullptr, 'v'},
|
||||
{"warning", required_argument, nullptr, 'W'},
|
||||
{"wramx", no_argument, nullptr, 'w'},
|
||||
{"nopad", no_argument, nullptr, 'x'},
|
||||
{nullptr, no_argument, nullptr, 0 }
|
||||
@@ -347,6 +348,9 @@ int main(int argc, char *argv[]) {
|
||||
beVerbose = true;
|
||||
break;
|
||||
// LCOV_EXCL_STOP
|
||||
case 'W':
|
||||
warnings.processWarningFlag(musl_optarg);
|
||||
break;
|
||||
case 'w':
|
||||
isWRAM0Mode = true;
|
||||
break;
|
||||
|
||||
@@ -33,6 +33,25 @@ static void pushRPN(int32_t value, bool comesFromError) {
|
||||
// has popped any values with the error flag set.
|
||||
static bool isError = false;
|
||||
|
||||
#define diagnosticAt(patch, id, ...) \
|
||||
do { \
|
||||
bool errorDiag = warnings.getWarningBehavior(id) == WarningBehavior::ERROR; \
|
||||
if (!isError || !errorDiag) { \
|
||||
warningAt(patch, id, __VA_ARGS__); \
|
||||
} \
|
||||
if (errorDiag) { \
|
||||
isError = true; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define firstErrorAt(...) \
|
||||
do { \
|
||||
if (!isError) { \
|
||||
errorAt(__VA_ARGS__); \
|
||||
isError = true; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int32_t popRPN(Patch const &patch) {
|
||||
if (rpnStack.empty()) {
|
||||
fatalAt(patch, "Internal error, RPN stack empty");
|
||||
@@ -98,23 +117,26 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
case RPN_DIV:
|
||||
value = popRPN(patch);
|
||||
if (value == 0) {
|
||||
if (!isError) {
|
||||
errorAt(patch, "Division by 0");
|
||||
isError = true;
|
||||
}
|
||||
firstErrorAt(patch, "Division by 0");
|
||||
popRPN(patch);
|
||||
value = INT32_MAX;
|
||||
value = 0;
|
||||
} else if (int32_t lval = popRPN(patch); lval == INT32_MIN && value == -1) {
|
||||
diagnosticAt(
|
||||
patch,
|
||||
WARNING_DIV,
|
||||
"Division of %" PRId32 " by -1 yields %" PRId32,
|
||||
INT32_MIN,
|
||||
INT32_MIN
|
||||
);
|
||||
value = INT32_MIN;
|
||||
} else {
|
||||
value = op_divide(popRPN(patch), value);
|
||||
value = op_divide(lval, value);
|
||||
}
|
||||
break;
|
||||
case RPN_MOD:
|
||||
value = popRPN(patch);
|
||||
if (value == 0) {
|
||||
if (!isError) {
|
||||
errorAt(patch, "Modulo by 0");
|
||||
isError = true;
|
||||
}
|
||||
firstErrorAt(patch, "Modulo by 0");
|
||||
popRPN(patch);
|
||||
value = 0;
|
||||
} else {
|
||||
@@ -127,10 +149,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
case RPN_EXP:
|
||||
value = popRPN(patch);
|
||||
if (value < 0) {
|
||||
if (!isError) {
|
||||
errorAt(patch, "Exponent by negative value %" PRId32, value);
|
||||
isError = true;
|
||||
}
|
||||
firstErrorAt(patch, "Exponent by negative value %" PRId32, value);
|
||||
popRPN(patch);
|
||||
value = 0;
|
||||
} else {
|
||||
@@ -204,14 +223,49 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
|
||||
case RPN_SHL:
|
||||
value = popRPN(patch);
|
||||
if (value < 0) {
|
||||
diagnosticAt(
|
||||
patch, WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %" PRId32, value
|
||||
);
|
||||
}
|
||||
if (value >= 32) {
|
||||
diagnosticAt(
|
||||
patch, WARNING_SHIFT_AMOUNT, "Shifting left by large amount %" PRId32, value
|
||||
);
|
||||
}
|
||||
value = op_shift_left(popRPN(patch), value);
|
||||
break;
|
||||
case RPN_SHR:
|
||||
case RPN_SHR: {
|
||||
value = popRPN(patch);
|
||||
value = op_shift_right(popRPN(patch), value);
|
||||
int32_t lval = popRPN(patch);
|
||||
if (lval < 0) {
|
||||
diagnosticAt(patch, WARNING_SHIFT, "Shifting right negative value %" PRId32, lval);
|
||||
}
|
||||
if (value < 0) {
|
||||
diagnosticAt(
|
||||
patch, WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %" PRId32, value
|
||||
);
|
||||
}
|
||||
if (value >= 32) {
|
||||
diagnosticAt(
|
||||
patch, WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32, value
|
||||
);
|
||||
}
|
||||
value = op_shift_right(lval, value);
|
||||
break;
|
||||
}
|
||||
case RPN_USHR:
|
||||
value = popRPN(patch);
|
||||
if (value < 0) {
|
||||
diagnosticAt(
|
||||
patch, WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %" PRId32, value
|
||||
);
|
||||
}
|
||||
if (value >= 32) {
|
||||
diagnosticAt(
|
||||
patch, WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32, value
|
||||
);
|
||||
}
|
||||
value = op_shift_right_unsigned(popRPN(patch), value);
|
||||
break;
|
||||
|
||||
@@ -324,14 +378,13 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
case RPN_HRAM:
|
||||
value = popRPN(patch);
|
||||
if (value < 0 || (value > 0xFF && value < 0xFF00) || value > 0xFFFF) {
|
||||
if (!isError) {
|
||||
errorAt(patch, "Address $%" PRIx32 " for LDH is not in HRAM range", value);
|
||||
isError = true;
|
||||
}
|
||||
firstErrorAt(patch, "Address $%" PRIx32 " for LDH is not in HRAM range", value);
|
||||
value = 0;
|
||||
} else if (value >= 0 && value <= 0xFF) {
|
||||
warningAt(
|
||||
patch, "LDH is deprecated with values from $00 to $FF; use $FF00 to $FFFF"
|
||||
patch,
|
||||
WARNING_OBSOLETE,
|
||||
"LDH is deprecated with values from $00 to $FF; use $FF00 to $FFFF"
|
||||
);
|
||||
}
|
||||
value &= 0xFF;
|
||||
@@ -341,10 +394,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
value = popRPN(patch);
|
||||
// Acceptable values are 0x00, 0x08, 0x10, ..., 0x38
|
||||
if (value & ~0x38) {
|
||||
if (!isError) {
|
||||
errorAt(patch, "Value $%" PRIx32 " is not a RST vector", value);
|
||||
isError = true;
|
||||
}
|
||||
firstErrorAt(patch, "Value $%" PRIx32 " is not a RST vector", value);
|
||||
value = 0;
|
||||
}
|
||||
value |= 0xC7;
|
||||
@@ -355,10 +405,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
int32_t mask = getRPNByte(expression, size, patch);
|
||||
// Acceptable values are 0 to 7
|
||||
if (value & ~0x07) {
|
||||
if (!isError) {
|
||||
errorAt(patch, "Value $%" PRIx32 " is not a bit index", value);
|
||||
isError = true;
|
||||
}
|
||||
firstErrorAt(patch, "Value $%" PRIx32 " is not a bit index", value);
|
||||
value = 0;
|
||||
}
|
||||
value = mask | (value << 3);
|
||||
@@ -437,6 +484,7 @@ void patch_CheckAssertions() {
|
||||
case ASSERT_WARN:
|
||||
warningAt(
|
||||
assert.patch,
|
||||
WARNING_ASSERT,
|
||||
"%s",
|
||||
!assert.message.empty() ? assert.message.c_str() : "assert failure"
|
||||
);
|
||||
@@ -486,8 +534,8 @@ static void applyFilePatches(Section §ion, Section &dataSection) {
|
||||
uint16_t address = patch.pcSection->org + patch.pcOffset + 2;
|
||||
int16_t jumpOffset = value - address;
|
||||
|
||||
if (!isError && (jumpOffset < -128 || jumpOffset > 127)) {
|
||||
errorAt(
|
||||
if (jumpOffset < -128 || jumpOffset > 127) {
|
||||
firstErrorAt(
|
||||
patch,
|
||||
"JR target must be between -128 and 127 bytes away, not %" PRId16
|
||||
"; use JP instead",
|
||||
@@ -497,12 +545,13 @@ static void applyFilePatches(Section §ion, Section &dataSection) {
|
||||
dataSection.data[offset] = jumpOffset & 0xFF;
|
||||
} else {
|
||||
// Patch a certain number of bytes
|
||||
if (!isError && (value < type.min || value > type.max)) {
|
||||
errorAt(
|
||||
if (value < type.min || value > type.max) {
|
||||
diagnosticAt(
|
||||
patch,
|
||||
"Value %" PRId32 "%s is not %u-bit",
|
||||
WARNING_TRUNCATION,
|
||||
"Value $%" PRIx32 "%s is not %u-bit",
|
||||
value,
|
||||
value < 0 ? " (maybe negative?)" : "",
|
||||
value < 0 ? " (may be negative?)" : "",
|
||||
type.size * 8U
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,14 +9,43 @@
|
||||
|
||||
static uint32_t nbErrors = 0;
|
||||
|
||||
// clang-format off: nested initializers
|
||||
Diagnostics<WarningLevel, WarningID> warnings = {
|
||||
.metaWarnings = {
|
||||
{"all", LEVEL_ALL },
|
||||
{"everything", LEVEL_EVERYTHING},
|
||||
},
|
||||
.warningFlags = {
|
||||
{"assert", LEVEL_DEFAULT },
|
||||
{"div", LEVEL_ALL },
|
||||
{"obsolete", LEVEL_DEFAULT },
|
||||
{"shift", LEVEL_ALL },
|
||||
{"shift-amount", LEVEL_ALL },
|
||||
{"truncation", LEVEL_DEFAULT },
|
||||
},
|
||||
.paramWarnings = {},
|
||||
.state = DiagnosticsState<WarningID>(),
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
static void printDiag(
|
||||
FileStackNode const *src, uint32_t lineNo, char const *fmt, va_list args, char const *type
|
||||
FileStackNode const *src,
|
||||
uint32_t lineNo,
|
||||
char const *fmt,
|
||||
va_list args,
|
||||
char const *type,
|
||||
char const *flagfmt,
|
||||
char const *flag
|
||||
) {
|
||||
fprintf(stderr, "%s: ", type);
|
||||
if (src) {
|
||||
src->dump(lineNo);
|
||||
fputs(": ", stderr);
|
||||
}
|
||||
if (flagfmt) {
|
||||
fprintf(stderr, flagfmt, flag);
|
||||
fputs("\n ", stderr);
|
||||
}
|
||||
vfprintf(stderr, fmt, args);
|
||||
putc('\n', stderr);
|
||||
}
|
||||
@@ -42,21 +71,21 @@ static void abortLinking(char const *verb) {
|
||||
void warning(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
printDiag(src, lineNo, fmt, args, "warning");
|
||||
printDiag(src, lineNo, fmt, args, "warning", nullptr, 0);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void warning(char const *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
printDiag(nullptr, 0, fmt, args, "warning");
|
||||
printDiag(nullptr, 0, fmt, args, "warning", nullptr, 0);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void error(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
printDiag(src, lineNo, fmt, args, "error");
|
||||
printDiag(src, lineNo, fmt, args, "error", nullptr, 0);
|
||||
va_end(args);
|
||||
|
||||
incrementErrors();
|
||||
@@ -65,7 +94,7 @@ void error(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
|
||||
void error(char const *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
printDiag(nullptr, 0, fmt, args, "error");
|
||||
printDiag(nullptr, 0, fmt, args, "error", nullptr, 0);
|
||||
va_end(args);
|
||||
|
||||
incrementErrors();
|
||||
@@ -96,7 +125,7 @@ void argErr(char flag, char const *fmt, ...) {
|
||||
void fatal(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
printDiag(src, lineNo, fmt, args, "FATAL");
|
||||
printDiag(src, lineNo, fmt, args, "FATAL", nullptr, 0);
|
||||
va_end(args);
|
||||
|
||||
incrementErrors();
|
||||
@@ -107,7 +136,7 @@ void fatal(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
|
||||
void fatal(char const *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
printDiag(nullptr, 0, fmt, args, "FATAL");
|
||||
printDiag(nullptr, 0, fmt, args, "FATAL", nullptr, 0);
|
||||
va_end(args);
|
||||
|
||||
incrementErrors();
|
||||
@@ -119,3 +148,27 @@ void requireZeroErrors() {
|
||||
abortLinking("failed");
|
||||
}
|
||||
}
|
||||
|
||||
void warning(FileStackNode const *src, uint32_t lineNo, WarningID id, char const *fmt, ...) {
|
||||
char const *flag = warnings.warningFlags[id].name;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
switch (warnings.getWarningBehavior(id)) {
|
||||
case WarningBehavior::DISABLED:
|
||||
break;
|
||||
|
||||
case WarningBehavior::ENABLED:
|
||||
printDiag(src, lineNo, fmt, args, "warning", "[-W%s]", flag);
|
||||
break;
|
||||
|
||||
case WarningBehavior::ERROR:
|
||||
printDiag(src, lineNo, fmt, args, "error", "[-Werror=%s]", flag);
|
||||
|
||||
incrementErrors();
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
warning: assert.asm(5): Worry about me, but not too much.
|
||||
warning: assert.asm(5): [-Wassert]
|
||||
Worry about me, but not too much.
|
||||
error: assert.asm(6): Okay, this is getting serious!
|
||||
FATAL: assert.asm(7): It all ends now.
|
||||
Linking aborted with 2 errors
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
error: invalid-patches.asm(10): JR target must be between -128 and 127 bytes away, not 190; use JP instead
|
||||
warning: invalid-patches.asm(9): LDH is deprecated with values from $00 to $FF; use $FF00 to $FFFF
|
||||
warning: invalid-patches.asm(9): [-Wobsolete]
|
||||
LDH is deprecated with values from $00 to $FF; use $FF00 to $FFFF
|
||||
error: invalid-patches.asm(8): Requested SIZEOF() of section "NonexistentSection", which was not found
|
||||
error: invalid-patches.asm(7): Requested STARTOF() of section "NonexistentSection", which was not found
|
||||
error: invalid-patches.asm(6): Requested BANK() of section "NonexistentSection", which was not found
|
||||
|
||||
10
test/link/patch-diagnostics.asm
Normal file
10
test/link/patch-diagnostics.asm
Normal file
@@ -0,0 +1,10 @@
|
||||
def fzero equs "startof(\"test\")"
|
||||
section "test", rom0
|
||||
ld a, $8000_0000 / (fzero - 1)
|
||||
ld a, 1 << (fzero - 1)
|
||||
ld a, 1 << (fzero + 32)
|
||||
ld a, (fzero - 1) >> 1
|
||||
ld a, 1 >> (fzero - 1)
|
||||
ld a, 1 >> (fzero + 32)
|
||||
ld a, 1 >>> (fzero - 1)
|
||||
ld a, 1 >>> (fzero + 32)
|
||||
18
test/link/patch-diagnostics.out
Normal file
18
test/link/patch-diagnostics.out
Normal file
@@ -0,0 +1,18 @@
|
||||
warning: patch-diagnostics.asm(10): [-Wshift-amount]
|
||||
Shifting right by large amount 32
|
||||
warning: patch-diagnostics.asm(9): [-Wshift-amount]
|
||||
Shifting right by negative amount -1
|
||||
warning: patch-diagnostics.asm(8): [-Wshift-amount]
|
||||
Shifting right by large amount 32
|
||||
warning: patch-diagnostics.asm(7): [-Wshift-amount]
|
||||
Shifting right by negative amount -1
|
||||
warning: patch-diagnostics.asm(6): [-Wshift]
|
||||
Shifting right negative value -1
|
||||
warning: patch-diagnostics.asm(5): [-Wshift-amount]
|
||||
Shifting left by large amount 32
|
||||
warning: patch-diagnostics.asm(4): [-Wshift-amount]
|
||||
Shifting left by negative amount -1
|
||||
warning: patch-diagnostics.asm(3): [-Wdiv]
|
||||
Division of -2147483648 by -1 yields -2147483648
|
||||
warning: patch-diagnostics.asm(3): [-Wtruncation]
|
||||
Value $80000000 (may be negative?) is not 8-bit
|
||||
@@ -1,3 +1,4 @@
|
||||
error: patch-overflow.asm(3): Value 81920 is not 16-bit
|
||||
error: patch-overflow.asm(2): Value 16384 is not 8-bit
|
||||
Linking failed with 2 errors
|
||||
warning: patch-overflow.asm(3): [-Wtruncation]
|
||||
Value $14000 is not 16-bit
|
||||
warning: patch-overflow.asm(2): [-Wtruncation]
|
||||
Value $4000 is not 8-bit
|
||||
|
||||
@@ -71,7 +71,7 @@ tryCmpRomSize () {
|
||||
}
|
||||
|
||||
rgblinkQuiet () {
|
||||
out="$(env $RGBLINK "$@")" || return $?
|
||||
out="$(env $RGBLINK -Weverything "$@")" || return $?
|
||||
if [[ -n "$out" ]]; then
|
||||
echo "$bold${red}Linking shouldn't produce anything on stdout!${rescolors}${resbold}"
|
||||
false
|
||||
|
||||
Reference in New Issue
Block a user