diff --git a/include/asm/warning.hpp b/include/asm/warning.hpp index 2bfc24f5..d676b955 100644 --- a/include/asm/warning.hpp +++ b/include/asm/warning.hpp @@ -3,6 +3,8 @@ #ifndef RGBDS_ASM_WARNING_HPP #define RGBDS_ASM_WARNING_HPP +#include + #include "diagnostics.hpp" extern unsigned int nbErrors, maxErrors; @@ -78,7 +80,6 @@ void error(char const *fmt, ...); // affect the following code. The code will fail to assemble but the user will // get a list of all errors at the end, making it easier to fix all of them at // once. -[[gnu::format(printf, 1, 2)]] -void errorNoNewline(char const *fmt, ...); +void error(std::function callback); #endif // RGBDS_ASM_WARNING_HPP diff --git a/src/asm/output.cpp b/src/asm/output.cpp index dcc4a7c5..f4f6f8d5 100644 --- a/src/asm/output.cpp +++ b/src/asm/output.cpp @@ -552,7 +552,7 @@ void out_WriteState(std::string name, std::vector const &features) for (StateFeature feature : features) { fprintf(file, "\n; %s\n", dumpHeadings[feature]); if (!dumpFuncs[feature](file)) { - fprintf(file, "; No values\n"); + fputs("; No values\n", file); } } } diff --git a/src/asm/section.cpp b/src/asm/section.cpp index afb636ad..dfb18f23 100644 --- a/src/asm/section.cpp +++ b/src/asm/section.cpp @@ -256,10 +256,10 @@ static void mergeSections( break; case SECTION_NORMAL: - errorNoNewline("Section already defined previously at "); - sect.src->dump(sect.fileLine); - putc('\n', stderr); - nbSectErrors++; + sectError([&]() { + fputs("Section already defined previously at ", stderr); + sect.src->dump(sect.fileLine); + }); break; } } diff --git a/src/asm/symbol.cpp b/src/asm/symbol.cpp index 9476854a..49293863 100644 --- a/src/asm/symbol.cpp +++ b/src/asm/symbol.cpp @@ -115,11 +115,10 @@ static void dumpFilename(Symbol const &sym) { fputs(" at ", stderr); if (sym.src) { sym.src->dump(sym.fileLine); - putc('\n', stderr); } else if (sym.isBuiltin) { - fputs("\n", stderr); + fputs("", stderr); } else { - fputs("\n", stderr); + fputs("", stderr); } } @@ -144,20 +143,22 @@ static void alreadyDefinedError(Symbol const &sym, char const *asType) { // `DEF()` would return false, so we should not claim the symbol is already defined error("'%s' is reserved for a built-in symbol", sym.name.c_str()); } else { - errorNoNewline("'%s' already defined", sym.name.c_str()); - if (asType) { - fprintf(stderr, " as %s", asType); - } - dumpFilename(sym); - if (sym.type == SYM_EQUS) { - if (std::string const &contents = *sym.getEqus(); isValidIdentifier(contents)) { - fprintf( - stderr, - " (should it be {interpolated} to define its contents \"%s\"?)\n", - contents.c_str() - ); + error([&]() { + fprintf(stderr, "'%s' already defined", sym.name.c_str()); + if (asType) { + fprintf(stderr, " as %s", asType); } - } + dumpFilename(sym); + if (sym.type == SYM_EQUS) { + if (std::string const &contents = *sym.getEqus(); isValidIdentifier(contents)) { + fprintf( + stderr, + "\n (should it be {interpolated} to define its contents \"%s\"?)", + contents.c_str() + ); + } + } + }); } } @@ -372,8 +373,10 @@ static Symbol *createNonrelocSymbol(std::string const &symName, bool numeric) { return nullptr; // Don't allow overriding the symbol, that'd be bad! } else if (!numeric) { // The symbol has already been referenced, but it's not allowed - errorNoNewline("'%s' already referenced", symName.c_str()); - dumpFilename(*sym); + error([&]() { + fprintf(stderr, "'%s' already referenced", symName.c_str()); + dumpFilename(*sym); + }); return nullptr; // Don't allow overriding the symbol, that'd be bad! } @@ -438,8 +441,10 @@ Symbol *sym_RedefString(std::string const &symName, std::shared_ptr if (sym->isDefined()) { alreadyDefinedError(*sym, "non-EQUS"); } else { - errorNoNewline("'%s' already referenced", symName.c_str()); - dumpFilename(*sym); + error([&]() { + fprintf(stderr, "'%s' already referenced", symName.c_str()); + dumpFilename(*sym); + }); } return nullptr; } else if (sym->isBuiltin) { diff --git a/src/asm/warning.cpp b/src/asm/warning.cpp index 63ebac30..44b4ef1a 100644 --- a/src/asm/warning.cpp +++ b/src/asm/warning.cpp @@ -78,13 +78,7 @@ static void printDiag( lexer_DumpStringExpansions(); } -void error(char const *fmt, ...) { - va_list args; - - va_start(args, fmt); - printDiag(fmt, args, "error", ":", nullptr); - va_end(args); - +static void incrementErrors() { // This intentionally makes 0 act as "unlimited" (or at least "limited to sizeof(unsigned)") nbErrors++; if (nbErrors == maxErrors) { @@ -97,26 +91,25 @@ void error(char const *fmt, ...) { } } -void errorNoNewline(char const *fmt, ...) { +void error(char const *fmt, ...) { va_list args; + va_start(args, fmt); + printDiag(fmt, args, "error", ":", nullptr); + va_end(args); + + incrementErrors(); +} + +void error(std::function callback) { fputs("error: ", stderr); fstk_DumpCurrent(); fputs(":\n ", stderr); - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); + callback(); + putc('\n', stderr); + lexer_DumpStringExpansions(); - // This intentionally makes 0 act as "unlimited" (or at least "limited to sizeof(unsigned)") - nbErrors++; - if (nbErrors == maxErrors) { - errx( - "The maximum of %u error%s was reached (configure with \"-X/--max-errors\"); assembly " - "aborted!", - maxErrors, - maxErrors == 1 ? "" : "s" - ); - } + incrementErrors(); } [[noreturn]] diff --git a/src/gfx/pal_packing.cpp b/src/gfx/pal_packing.cpp index 8d57624d..6a99a0ce 100644 --- a/src/gfx/pal_packing.cpp +++ b/src/gfx/pal_packing.cpp @@ -551,7 +551,7 @@ std::tuple, size_t> // LCOV_EXCL_START if (options.verbosity >= Options::VERB_INTERM) { for (auto &&assignment : assignments) { - fprintf(stderr, "{ "); + fputs("{ ", stderr); for (auto &&attrs : assignment) { fprintf(stderr, "[%zu] ", attrs.protoPalIndex); for (auto &&colorIndex : protoPalettes[attrs.protoPalIndex]) { @@ -570,7 +570,7 @@ std::tuple, size_t> // LCOV_EXCL_START if (options.verbosity >= Options::VERB_INTERM) { for (auto &&assignment : assignments) { - fprintf(stderr, "{ "); + fputs("{ ", stderr); for (auto &&attrs : assignment) { fprintf(stderr, "[%zu] ", attrs.protoPalIndex); for (auto &&colorIndex : protoPalettes[attrs.protoPalIndex]) { diff --git a/src/link/assign.cpp b/src/link/assign.cpp index 2da27b8a..428ad2be 100644 --- a/src/link/assign.cpp +++ b/src/link/assign.cpp @@ -392,7 +392,7 @@ void assign_AssignSections() { // Overlaying requires only fully-constrained sections verbosePrint("Assigning other sections...\n"); if (overlayFileName) { - fprintf(stderr, "FATAL: All sections must be fixed when using an overlay file"); + fputs("FATAL: All sections must be fixed when using an overlay file", stderr); uint8_t nbSections = 0; for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED; constraints >= 0; constraints--) { diff --git a/src/link/output.cpp b/src/link/output.cpp index b1583bb5..b4a0d1e8 100644 --- a/src/link/output.cpp +++ b/src/link/output.cpp @@ -480,9 +480,9 @@ static void writeMapBank(SortedSections const §List, SectionType type, uint3 if (sect->nextu) { // Announce the following "piece" if (sect->nextu->modifier == SECTION_UNION) { - fprintf(mapFile, "\t ; Next union\n"); + fputs("\t ; Next union\n", mapFile); } else if (sect->nextu->modifier == SECTION_FRAGMENT) { - fprintf(mapFile, "\t ; Next fragment\n"); + fputs("\t ; Next fragment\n", mapFile); } } } diff --git a/test/asm/error-limit.asm b/test/asm/error-limit.asm new file mode 100644 index 00000000..ea80a329 --- /dev/null +++ b/test/asm/error-limit.asm @@ -0,0 +1,2 @@ +def x equ 1 +def x equ 2 diff --git a/test/asm/error-limit.err b/test/asm/error-limit.err new file mode 100644 index 00000000..8680aa3c --- /dev/null +++ b/test/asm/error-limit.err @@ -0,0 +1,3 @@ +error: error-limit.asm(2): + 'x' already defined at error-limit.asm(1) +error: The maximum of 1 error was reached (configure with "-X/--max-errors"); assembly aborted! diff --git a/test/asm/error-limit.flags b/test/asm/error-limit.flags new file mode 100644 index 00000000..c8401c0e --- /dev/null +++ b/test/asm/error-limit.flags @@ -0,0 +1 @@ +-Weverything -X 1 diff --git a/test/asm/invalid-numbers.asm b/test/asm/invalid-numbers.asm index cb0c033c..382d792f 100644 --- a/test/asm/invalid-numbers.asm +++ b/test/asm/invalid-numbers.asm @@ -1,6 +1,9 @@ ; no digits def x = $ def x = ` +def x = 0b +def x = 0o +def x = 0x ; too large def x = 9_876_543_210 diff --git a/test/asm/invalid-numbers.err b/test/asm/invalid-numbers.err index fbd67c11..f2730b31 100644 --- a/test/asm/invalid-numbers.err +++ b/test/asm/invalid-numbers.err @@ -2,18 +2,24 @@ error: invalid-numbers.asm(2): Invalid integer constant, no digits after '$' error: invalid-numbers.asm(3): Invalid graphics constant, no digits after '`' -warning: invalid-numbers.asm(6): [-Wlarge-constant] - Integer constant is too large -warning: invalid-numbers.asm(7): [-Wlarge-constant] - Integer constant is too large -warning: invalid-numbers.asm(8): [-Wlarge-constant] - Integer constant is too large +error: invalid-numbers.asm(4): + Invalid integer constant, no digits after '%' +error: invalid-numbers.asm(5): + Invalid integer constant, no digits after '&' +error: invalid-numbers.asm(6): + Invalid integer constant, no digits after '$' warning: invalid-numbers.asm(9): [-Wlarge-constant] Integer constant is too large warning: invalid-numbers.asm(10): [-Wlarge-constant] + Integer constant is too large +warning: invalid-numbers.asm(11): [-Wlarge-constant] + Integer constant is too large +warning: invalid-numbers.asm(12): [-Wlarge-constant] + Integer constant is too large +warning: invalid-numbers.asm(13): [-Wlarge-constant] Magnitude of fixed-point constant is too large -error: invalid-numbers.asm(13): - Invalid fixed-point constant, no significant digits after 'q' error: invalid-numbers.asm(16): + Invalid fixed-point constant, no significant digits after 'q' +error: invalid-numbers.asm(19): Fixed-point constant precision must be between 1 and 31 -error: Assembly aborted (4 errors)! +error: Assembly aborted (7 errors)! diff --git a/test/asm/invalid-param.asm b/test/asm/invalid-param.asm new file mode 100644 index 00000000..0bb8baaa --- /dev/null +++ b/test/asm/invalid-param.asm @@ -0,0 +1,3 @@ +section "test", rom0 +ld a, 256 +ld a, -129 diff --git a/test/asm/invalid-param.err b/test/asm/invalid-param.err new file mode 100644 index 00000000..f2c6b42f --- /dev/null +++ b/test/asm/invalid-param.err @@ -0,0 +1,5 @@ +warning: Invalid parameter 99 for warning flag "truncation"; capping at maximum 2 +warning: invalid-param.asm(2): [-Wtruncation] + Expression must be 8-bit; use LOW() to force 8-bit +warning: invalid-param.asm(3): [-Wtruncation] + Expression must be 8-bit; use LOW() to force 8-bit diff --git a/test/asm/invalid-param.flags b/test/asm/invalid-param.flags new file mode 100644 index 00000000..5e6a4d2e --- /dev/null +++ b/test/asm/invalid-param.flags @@ -0,0 +1 @@ +-Weverything -Wtruncation=99