diff --git a/include/asm/warning.hpp b/include/asm/warning.hpp index dd068e0d..902ccbcb 100644 --- a/include/asm/warning.hpp +++ b/include/asm/warning.hpp @@ -62,7 +62,7 @@ void processWarningFlag(char const *flag); * Used to warn the user about problems that don't prevent the generation of * valid code. */ -void warning(WarningID id, char const *fmt, ...) format_(printf, 2, 3); +[[gnu::format(printf, 2, 3)]] void warning(WarningID id, char const *fmt, ...); /* * Used for errors that compromise the whole assembly process by affecting the @@ -71,7 +71,7 @@ void warning(WarningID id, char const *fmt, ...) format_(printf, 2, 3); * It is also used when the assembler goes into an invalid state (for example, * when it fails to allocate memory). */ -[[noreturn]] void fatalerror(char const *fmt, ...) format_(printf, 1, 2); +[[gnu::format(printf, 1, 2), noreturn]] void fatalerror(char const *fmt, ...); /* * Used for errors that make it impossible to assemble correctly, but don't @@ -79,6 +79,6 @@ void warning(WarningID id, char const *fmt, ...) format_(printf, 2, 3); * get a list of all errors at the end, making it easier to fix all of them at * once. */ -void error(char const *fmt, ...) format_(printf, 1, 2); +[[gnu::format(printf, 1, 2)]] void error(char const *fmt, ...); #endif // WARNING_H diff --git a/include/error.hpp b/include/error.hpp index a735d4f9..3b686f8f 100644 --- a/include/error.hpp +++ b/include/error.hpp @@ -3,16 +3,15 @@ #ifndef RGBDS_ERROR_H #define RGBDS_ERROR_H -#include "helpers.hpp" #include "platform.hpp" extern "C" { -void warn(char const *fmt...) format_(printf, 1, 2); -void warnx(char const *fmt, ...) format_(printf, 1, 2); +[[gnu::format(printf, 1, 2)]] void warn(char const *fmt...); +[[gnu::format(printf, 1, 2)]] void warnx(char const *fmt, ...); -[[noreturn]] void err(char const *fmt, ...) format_(printf, 1, 2); -[[noreturn]] void errx(char const *fmt, ...) format_(printf, 1, 2); +[[gnu::format(printf, 1, 2), noreturn]] void err(char const *fmt, ...); +[[gnu::format(printf, 1, 2), noreturn]] void errx(char const *fmt, ...); } #endif // RGBDS_ERROR_H diff --git a/include/gfx/main.hpp b/include/gfx/main.hpp index d89c9330..6fd1fa41 100644 --- a/include/gfx/main.hpp +++ b/include/gfx/main.hpp @@ -58,7 +58,7 @@ struct Options { static constexpr uint8_t VERB_DEBUG = 4; // Internals are logged static constexpr uint8_t VERB_UNMAPPED = 5; // Unused so far static constexpr uint8_t VERB_VVVVVV = 6; // What, can't I have a little fun? - format_(printf, 3, 4) void verbosePrint(uint8_t level, char const *fmt, ...) const; + [[gnu::format(printf, 3, 4)]] void verbosePrint(uint8_t level, char const *fmt, ...) const; mutable bool hasTransparentPixels = false; uint8_t maxOpaqueColors() const { return nbColorsPerPal - hasTransparentPixels; } @@ -73,11 +73,11 @@ extern Options options; /* * Prints a warning, and does not change the error count */ -void warning(char const *fmt, ...) format_(printf, 1, 2); +[[gnu::format(printf, 1, 2)]] void warning(char const *fmt, ...); /* * Prints an error, and increments the error count */ -void error(char const *fmt, ...) format_(printf, 1, 2); +[[gnu::format(printf, 1, 2)]] void error(char const *fmt, ...); /* * Prints an error, and increments the error count * Does not take format arguments so `format_` and `-Wformat-security` won't complain about @@ -87,7 +87,7 @@ void errorMessage(char const *msg); /* * Prints a fatal error, increments the error count, and gives up */ -[[noreturn]] void fatal(char const *fmt, ...) format_(printf, 1, 2); +[[gnu::format(printf, 1, 2), noreturn]] void fatal(char const *fmt, ...); struct Palette { // An array of 4 GBC-native (RGB555) colors diff --git a/include/helpers.hpp b/include/helpers.hpp index 5186a47d..5ad570d0 100644 --- a/include/helpers.hpp +++ b/include/helpers.hpp @@ -5,9 +5,6 @@ // Ideally, we'd use `__has_attribute` and `__has_builtin`, but these were only introduced in GCC 9 #ifdef __GNUC__ // GCC or compatible - #define format_(archetype, str_index, first_arg) \ - __attribute__((format(archetype, str_index, first_arg))) - #define attr_(...) __attribute__((__VA_ARGS__)) // In release builds, define "unreachable" as such, but trap in debug builds #ifdef NDEBUG #define unreachable_ __builtin_unreachable @@ -15,9 +12,6 @@ #define unreachable_ __builtin_trap #endif #else - // Unsupported, but no need to throw a fit - #define format_(archetype, str_index, first_arg) - #define attr_(...) // This seems to generate similar code to __builtin_unreachable, despite different semantics // Note that executing this is undefined behavior (declared [[noreturn]], but does return) [[noreturn]] static inline void unreachable_() { diff --git a/include/link/main.hpp b/include/link/main.hpp index f2ea3cef..7eb85da2 100644 --- a/include/link/main.hpp +++ b/include/link/main.hpp @@ -59,10 +59,11 @@ struct FileStackNode { std::string const &dump(uint32_t curLineNo) const; }; -void warning(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) - format_(printf, 3, 4); -void error(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4); -[[noreturn]] void fatal(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) - format_(printf, 3, 4); +[[gnu::format(printf, 3, 4)]] void + warning(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...); +[[gnu::format(printf, 3, 4)]] void + error(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...); +[[gnu::format(printf, 3, 4), noreturn]] void + fatal(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...); #endif // RGBDS_LINK_MAIN_H diff --git a/src/asm/format.cpp b/src/asm/format.cpp index 6b5dc7f3..d4292a21 100644 --- a/src/asm/format.cpp +++ b/src/asm/format.cpp @@ -45,7 +45,7 @@ void FormatSpec::useCharacter(int c) { case '0': if (state < FORMAT_WIDTH) padZero = true; - // fallthrough + [[fallthrough]]; case '1': case '2': case '3': diff --git a/src/asm/lexer.cpp b/src/asm/lexer.cpp index dd72443f..e0cb7091 100644 --- a/src/asm/lexer.cpp +++ b/src/asm/lexer.cpp @@ -864,7 +864,7 @@ static void discardBlockComment() { case '\r': // Handle CRLF before nextLine() since shiftChar updates colNo handleCRLF(c); - // fallthrough + [[fallthrough]]; case '\n': if (lexerState->expansions.empty()) nextLine(); @@ -879,7 +879,7 @@ static void discardBlockComment() { shiftChar(); return; } - // fallthrough + [[fallthrough]]; default: continue; } @@ -1216,7 +1216,7 @@ static void appendEscapedSubstring(std::string &yylval, std::string const &str) case '"': case '{': yylval += '\\'; - // fallthrough + [[fallthrough]]; default: yylval += c; break; @@ -1515,7 +1515,7 @@ static Token yylex_NORMAL() { case ';': discardComment(); - // fallthrough + [[fallthrough]]; case ' ': case '\t': break; @@ -1729,7 +1729,7 @@ static Token yylex_NORMAL() { case '\r': handleCRLF(c); - // fallthrough + [[fallthrough]]; case '\n': return Token(T_(NEWLINE)); @@ -1751,7 +1751,7 @@ static Token yylex_NORMAL() { shiftChar(); return Token(T_(STRING), readString(true)); } - // fallthrough + [[fallthrough]]; // Handle identifiers... or report garbage characters @@ -1846,7 +1846,7 @@ static Token yylex_RAW() { case ';': // Comments inside macro args discardComment(); c = peek(); - // fallthrough + [[fallthrough]]; case '\r': // End of line case '\n': case EOF: @@ -1920,7 +1920,7 @@ backslash: error("Illegal character escape %s\n", printChar(c)); break; } - // fallthrough + [[fallthrough]]; default: // Regular characters will just get copied append: diff --git a/src/asm/main.cpp b/src/asm/main.cpp index 136b90f1..7db7f373 100644 --- a/src/asm/main.cpp +++ b/src/asm/main.cpp @@ -198,7 +198,7 @@ int main(int argc, char *argv[]) { // introduced to better match the `-I dir` option of gcc and clang. case 'i': warning(WARNING_OBSOLETE, "`-i` is deprecated; use `-I`\n"); - // fallthrough + [[fallthrough]]; case 'I': fstk_AddIncludePath(musl_optarg); break; diff --git a/src/asm/section.cpp b/src/asm/section.cpp index b6eb1bda..73366012 100644 --- a/src/asm/section.cpp +++ b/src/asm/section.cpp @@ -47,7 +47,7 @@ std::optional currentLoadScope = std::nullopt; int32_t loadOffset; // Offset into the LOAD section's parent (see sect_GetOutputOffset) // A quick check to see if we have an initialized section -attr_(warn_unused_result) static bool checksection() { +[[nodiscard]] static bool checksection() { if (currentSection) return true; @@ -57,7 +57,7 @@ attr_(warn_unused_result) static bool checksection() { // A quick check to see if we have an initialized section that can contain // this much initialized data -attr_(warn_unused_result) static bool checkcodesection() { +[[nodiscard]] static bool checkcodesection() { if (!checksection()) return false; @@ -71,7 +71,7 @@ attr_(warn_unused_result) static bool checkcodesection() { return false; } -attr_(warn_unused_result) static bool checkSectionSize(Section const §, uint32_t size) { +[[nodiscard]] static bool checkSectionSize(Section const §, uint32_t size) { uint32_t maxSize = sectionTypeInfo[sect.type].size; // If the new size is reasonable, keep going @@ -88,7 +88,7 @@ attr_(warn_unused_result) static bool checkSectionSize(Section const §, uint } // Check if the section has grown too much. -attr_(warn_unused_result) static bool reserveSpace(uint32_t delta_size) { +[[nodiscard]] static bool reserveSpace(uint32_t delta_size) { // This check is here to trap broken code that generates sections that are too big and to // prevent the assembler from generating huge object files or trying to allocate too much // memory. diff --git a/src/fix/main.cpp b/src/fix/main.cpp index 57bab404..8bd964df 100644 --- a/src/fix/main.cpp +++ b/src/fix/main.cpp @@ -76,7 +76,7 @@ static void printUsage() { static uint8_t nbErrors; -static format_(printf, 1, 2) void report(char const *fmt, ...) { +[[gnu::format(printf, 1, 2)]] static void report(char const *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -465,7 +465,7 @@ static MbcType parseMBC(char const *name) { static_assert(MBC1 + 2 == MBC1_RAM_BATTERY, "Enum sanity check failed!"); static_assert(MMM01 + 1 == MMM01_RAM, "Enum sanity check failed!"); static_assert(MMM01 + 2 == MMM01_RAM_BATTERY, "Enum sanity check failed!"); - // fallthrough + [[fallthrough]]; case MBC1: case MMM01: if (features == RAM) diff --git a/src/link/sdas_obj.cpp b/src/link/sdas_obj.cpp index d7206b41..0213d1c5 100644 --- a/src/link/sdas_obj.cpp +++ b/src/link/sdas_obj.cpp @@ -50,11 +50,11 @@ retry: do { firstChar = getc(file); } while (firstChar != EOF && firstChar != '\r' && firstChar != '\n'); - // fallthrough + [[fallthrough]]; case '\r': if (firstChar == '\r' && getc(file) != '\n') consumeLF(where, lineNo, file); - // fallthrough + [[fallthrough]]; case '\n': goto retry; } @@ -65,7 +65,7 @@ retry: switch (c) { case '\r': consumeLF(where, lineNo, file); - // fallthrough + [[fallthrough]]; case '\n': case EOF: lineBuf.push_back('\0'); // Terminate the string (space was ensured above)