From ba4e58f4e0bcd3eead1cc82124d3a24baa433dfc Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:02:42 -0400 Subject: [PATCH] Add `-Wsingle-union` warning for `UNION` without `NEXTU` (#2170) --- contrib/bash_compl/_rgbasm.bash | 1 + contrib/zsh_compl/_rgbasm | 1 + include/asm/warning.hpp | 1 + man/rgbasm.1 | 6 ++++++ src/asm/section.cpp | 7 ++++++- src/asm/warning.cpp | 1 + test/asm/continues-after-missing-include/a.asm | 1 + test/asm/continues-after-missing-include/a.err | 2 +- test/asm/continues-after-missing-preinclude/a.asm | 1 + test/asm/continues-after-missing-preinclude/a.err | 2 +- test/asm/single-union.err | 2 ++ 11 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 test/asm/single-union.err diff --git a/contrib/bash_compl/_rgbasm.bash b/contrib/bash_compl/_rgbasm.bash index 5377ef00..a3f98746 100755 --- a/contrib/bash_compl/_rgbasm.bash +++ b/contrib/bash_compl/_rgbasm.bash @@ -193,6 +193,7 @@ _rgbasm_completions() { purge shift shift-amount + single-union truncation unmapped-char unmatched-directive diff --git a/contrib/zsh_compl/_rgbasm b/contrib/zsh_compl/_rgbasm index d65bc88d..af57af08 100644 --- a/contrib/zsh_compl/_rgbasm +++ b/contrib/zsh_compl/_rgbasm @@ -25,6 +25,7 @@ _rgbasm_warnings() { 'purge:Warn when purging exported symbols or labels' 'shift:Warn when shifting negative values' 'shift-amount:Warn when a shift'\''s operand is negative or \> 32' + 'single-union:Warn on UNION without NEXTU' 'truncation:Warn when implicit truncation loses bits' 'unmapped-char:Warn on unmapped character' 'unmatched-directive:Warn on unmatched directive pair' diff --git a/include/asm/warning.hpp b/include/asm/warning.hpp index 1a09121b..7b61ad2e 100644 --- a/include/asm/warning.hpp +++ b/include/asm/warning.hpp @@ -30,6 +30,7 @@ enum WarningID { WARNING_OBSOLETE, // Obsolete/deprecated things WARNING_SHIFT, // Undefined `SHIFT` behavior WARNING_SHIFT_AMOUNT, // Strange `SHIFT` amount + WARNING_SINGLE_UNION, // `UNION` without `NEXTU` WARNING_UNMATCHED_DIRECTIVE, // `PUSH[C|O|S]` without `POP[C|O|S]` WARNING_UNTERMINATED_LOAD, // `LOAD` without `ENDL` WARNING_USER, // User-defined `WARN`ings diff --git a/man/rgbasm.1 b/man/rgbasm.1 index 641aa6cd..5d532795 100644 --- a/man/rgbasm.1 +++ b/man/rgbasm.1 @@ -517,6 +517,12 @@ Warn when shifting right a negative value. 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 Wsingle-union +Warn when a +.Ic UNION +construct has no +.Ic NEXTU +alternatives. .It Fl Wtruncation= Warn when an implicit truncation (for example, .Ic db diff --git a/src/asm/section.cpp b/src/asm/section.cpp index cdd59405..6b6d4e94 100644 --- a/src/asm/section.cpp +++ b/src/asm/section.cpp @@ -38,6 +38,7 @@ using namespace std::literals; struct UnionStackEntry { uint32_t start; uint32_t size; + bool hasNextu; }; struct SectionStackEntry { @@ -782,7 +783,7 @@ void sect_StartUnion() { return; } - currentUnionStack.push({.start = curOffset, .size = 0}); + currentUnionStack.push({.start = curOffset, .size = 0, .hasNextu = false}); } static void endUnionMember() { @@ -801,6 +802,7 @@ void sect_NextUnionMember() { return; } endUnionMember(); + currentUnionStack.top().hasNextu = true; } void sect_EndUnion() { @@ -808,6 +810,9 @@ void sect_EndUnion() { error("Found `ENDU` outside of a `UNION` construct"); return; } + if (!currentUnionStack.top().hasNextu) { + warning(WARNING_SINGLE_UNION, "`UNION` construct has no `NEXTU` alternatives"); + } endUnionMember(); curOffset += currentUnionStack.top().size; currentUnionStack.pop(); diff --git a/src/asm/warning.cpp b/src/asm/warning.cpp index 49863212..86d2e7ba 100644 --- a/src/asm/warning.cpp +++ b/src/asm/warning.cpp @@ -37,6 +37,7 @@ Diagnostics warnings = { {"obsolete", LEVEL_DEFAULT }, {"shift", LEVEL_EVERYTHING}, {"shift-amount", LEVEL_EVERYTHING}, + {"single-union", LEVEL_EVERYTHING}, {"unmatched-directive", LEVEL_EXTRA }, {"unterminated-load", LEVEL_EXTRA }, {"user", LEVEL_DEFAULT }, diff --git a/test/asm/continues-after-missing-include/a.asm b/test/asm/continues-after-missing-include/a.asm index 63caab8a..25de3207 100644 --- a/test/asm/continues-after-missing-include/a.asm +++ b/test/asm/continues-after-missing-include/a.asm @@ -5,6 +5,7 @@ SECTION "test", WRAM0 UNION INCLUDE "nonexistent1.inc" WARN "still going!" +NEXTU INCLUDE "nonexistent2.inc" WARN "and going!" ENDU diff --git a/test/asm/continues-after-missing-include/a.err b/test/asm/continues-after-missing-include/a.err index a5894667..066c77a5 100644 --- a/test/asm/continues-after-missing-include/a.err +++ b/test/asm/continues-after-missing-include/a.err @@ -1,4 +1,4 @@ warning: still going! [-Wuser] at continues-after-missing-include/a.asm(7) warning: and going! [-Wuser] - at continues-after-missing-include/a.asm(9) + at continues-after-missing-include/a.asm(10) diff --git a/test/asm/continues-after-missing-preinclude/a.asm b/test/asm/continues-after-missing-preinclude/a.asm index 63caab8a..25de3207 100644 --- a/test/asm/continues-after-missing-preinclude/a.asm +++ b/test/asm/continues-after-missing-preinclude/a.asm @@ -5,6 +5,7 @@ SECTION "test", WRAM0 UNION INCLUDE "nonexistent1.inc" WARN "still going!" +NEXTU INCLUDE "nonexistent2.inc" WARN "and going!" ENDU diff --git a/test/asm/continues-after-missing-preinclude/a.err b/test/asm/continues-after-missing-preinclude/a.err index b2295489..11dc61e6 100644 --- a/test/asm/continues-after-missing-preinclude/a.err +++ b/test/asm/continues-after-missing-preinclude/a.err @@ -1,4 +1,4 @@ warning: still going! [-Wuser] at continues-after-missing-preinclude/a.asm(7) warning: and going! [-Wuser] - at continues-after-missing-preinclude/a.asm(9) + at continues-after-missing-preinclude/a.asm(10) diff --git a/test/asm/single-union.err b/test/asm/single-union.err new file mode 100644 index 00000000..2269f034 --- /dev/null +++ b/test/asm/single-union.err @@ -0,0 +1,2 @@ +warning: `UNION` construct has no `NEXTU` alternatives [-Wsingle-union] + at single-union.asm(4)