From 0c5570343857570493deadf4b7933bebf5a31a0d Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 26 Oct 2020 15:03:37 +0100 Subject: [PATCH] Improve helpers.h Use C11 standard _Noreturn instead of attributes (except, of course, MSVC) Remove unused helpers Avoid trapping in release builds, in favor of just unreachability Improve shim when __builtin_* are not available --- include/asm/warning.h | 2 +- include/extern/err.h | 8 ++++---- include/helpers.h | 35 ++++++++++++++++++++++------------- include/link/main.h | 2 +- src/asm/warning.c | 4 ++-- src/extern/err.c | 8 ++++---- src/link/assign.c | 2 +- src/link/main.c | 2 +- src/link/script.c | 6 +++--- src/link/section.c | 2 +- 10 files changed, 40 insertions(+), 31 deletions(-) diff --git a/include/asm/warning.h b/include/asm/warning.h index b76f4c65..c84394c7 100644 --- a/include/asm/warning.h +++ b/include/asm/warning.h @@ -55,7 +55,7 @@ void warning(enum WarningID id, const char *fmt, ...); * It is also used when the assembler goes into an invalid state (for example, * when it fails to allocate memory). */ -noreturn_ void fatalerror(const char *fmt, ...); +_Noreturn void fatalerror(const char *fmt, ...); /* * Used for errors that make it impossible to assemble correctly, but don't diff --git a/include/extern/err.h b/include/extern/err.h index cc5ff3a0..bbe5d39b 100644 --- a/include/extern/err.h +++ b/include/extern/err.h @@ -34,10 +34,10 @@ void vwarn(const char *fmt, va_list ap) format_(printf, 1, 0); void warnx(const char *fmt, ...) format_(printf, 1, 2); void vwarnx(const char *fmt, va_list ap) format_(printf, 1, 0); -noreturn_ void err(int status, const char *fmt, ...) format_(printf, 2, 3); -noreturn_ void verr(int status, const char *fmt, va_list ap) format_(printf, 2, 0); -noreturn_ void errx(int status, const char *fmt, ...) format_(printf, 2, 3); -noreturn_ void verrx(int status, const char *fmt, va_list ap) format_(printf, 2, 0); +_Noreturn void err(int status, const char *fmt, ...) format_(printf, 2, 3); +_Noreturn void verr(int status, const char *fmt, va_list ap) format_(printf, 2, 0); +_Noreturn void errx(int status, const char *fmt, ...) format_(printf, 2, 3); +_Noreturn void verrx(int status, const char *fmt, va_list ap) format_(printf, 2, 0); #endif /* ERR_IN_LIBC */ diff --git a/include/helpers.h b/include/helpers.h index f3cf99b8..59af3301 100644 --- a/include/helpers.h +++ b/include/helpers.h @@ -9,21 +9,30 @@ #ifndef HELPERS_H #define HELPERS_H -#ifdef __GNUC__ - /* GCC or compatible */ - #define format_(archetype, str_index, first_arg) \ - __attribute__ ((format (archetype, str_index, first_arg))) - #define noreturn_ __attribute__ ((noreturn)) - #define trap_ __builtin_trap() -#else - /* Unsupported, but no need to throw a fit */ - #define format_(archetype, str_index, first_arg) - #define noreturn_ - #define unused_ - #define trap_ +// Of course, MSVC does not support C11, so no _Noreturn there... +#ifdef _MSC_VER + #define _Noreturn __declspec(noreturn) #endif -/* Macros for stringification */ +// 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))) + // In release builds, define "unreachable" as such, but trap in debug builds + #ifdef NDEBUG + #define unreachable_ __builtin_unreachable + #else + #define unreachable_ __builtin_trap + #endif +#else + // Unsupported, but no need to throw a fit + #define format_(archetype, str_index, first_arg) + // This seems to generate similar code to __builtin_unreachable, despite different semantics + // Note that executing this is undefined behavior (declared _Noreturn, but does return) + static inline _Noreturn unreachable_(void) {} +#endif + +// Macros for stringification #define STR(x) #x #define EXPAND_AND_STR(x) STR(x) diff --git a/include/link/main.h b/include/link/main.h index d55e0a8e..a29915cf 100644 --- a/include/link/main.h +++ b/include/link/main.h @@ -66,7 +66,7 @@ void warning(struct FileStackNode const *where, uint32_t lineNo, void error(struct FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4); -noreturn_ void fatal(struct FileStackNode const *where, uint32_t lineNo, +_Noreturn void fatal(struct FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4); /** diff --git a/src/asm/warning.c b/src/asm/warning.c index 12a5e603..b764fa6e 100644 --- a/src/asm/warning.c +++ b/src/asm/warning.c @@ -222,7 +222,7 @@ void error(const char *fmt, ...) nbErrors++; } -noreturn_ void fatalerror(const char *fmt, ...) +_Noreturn void fatalerror(const char *fmt, ...) { va_list args; @@ -250,7 +250,7 @@ void warning(enum WarningID id, char const *fmt, ...) return; case WARNING_DEFAULT: - trap_; + unreachable_(); /* Not reached */ case WARNING_ENABLED: diff --git a/src/extern/err.c b/src/extern/err.c index c3d4bc33..086aad58 100644 --- a/src/extern/err.c +++ b/src/extern/err.c @@ -34,7 +34,7 @@ void rgbds_vwarnx(const char *fmt, va_list ap) putc('\n', stderr); } -noreturn_ void rgbds_verr(int status, const char *fmt, va_list ap) +_Noreturn void rgbds_verr(int status, const char *fmt, va_list ap) { fprintf(stderr, "error: "); if (fmt) { @@ -46,7 +46,7 @@ noreturn_ void rgbds_verr(int status, const char *fmt, va_list ap) exit(status); } -noreturn_ void rgbds_verrx(int status, const char *fmt, va_list ap) +_Noreturn void rgbds_verrx(int status, const char *fmt, va_list ap) { fprintf(stderr, "error"); if (fmt) { @@ -75,7 +75,7 @@ void rgbds_warnx(const char *fmt, ...) va_end(ap); } -noreturn_ void rgbds_err(int status, const char *fmt, ...) +_Noreturn void rgbds_err(int status, const char *fmt, ...) { va_list ap; @@ -84,7 +84,7 @@ noreturn_ void rgbds_err(int status, const char *fmt, ...) va_end(ap); } -noreturn_ void rgbds_errx(int status, const char *fmt, ...) +_Noreturn void rgbds_errx(int status, const char *fmt, ...) { va_list ap; diff --git a/src/link/assign.c b/src/link/assign.c index 64244f01..bb620446 100644 --- a/src/link/assign.c +++ b/src/link/assign.c @@ -439,7 +439,7 @@ void assign_AssignSections(void) return; } - trap_; + unreachable_(); } void assign_Cleanup(void) diff --git a/src/link/main.c b/src/link/main.c index 8d2b5a58..00bc1ae3 100644 --- a/src/link/main.c +++ b/src/link/main.c @@ -99,7 +99,7 @@ void error(struct FileStackNode const *where, uint32_t lineNo, char const *fmt, nbErrors++; } -noreturn_ void fatal(struct FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) +_Noreturn void fatal(struct FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) { va_list ap; diff --git a/src/link/script.c b/src/link/script.c index e3f180ee..30129ce6 100644 --- a/src/link/script.c +++ b/src/link/script.c @@ -318,7 +318,7 @@ static void processCommand(enum LinkerScriptCommand command, uint16_t arg, { switch (command) { case COMMAND_INVALID: - trap_; + unreachable_(); case COMMAND_ORG: break; @@ -391,12 +391,12 @@ struct SectionPlacement *script_NextSection(void) switch (parserState) { case PARSER_FIRSTTIME: - trap_; + unreachable_(); case PARSER_LINESTART: switch (token->type) { case TOKEN_INVALID: - trap_; + unreachable_(); case TOKEN_EOF: if (!popFile()) diff --git a/src/link/section.c b/src/link/section.c index e3938187..4dde6eff 100644 --- a/src/link/section.c +++ b/src/link/section.c @@ -108,7 +108,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se break; case SECTION_NORMAL: - trap_; + unreachable_(); } other->nextu = target->nextu;