pawn-lang / compiler

Pawn compiler for SA-MP with bug fixes and new features - runs on Windows, Linux, macOS
Other
303 stars 70 forks source link

Compiler calls overloaded operator `++` instead of `--` #627

Closed Daniel-Cortez closed 3 years ago

Daniel-Cortez commented 3 years ago

Issue description:

When using operator -- on a tagged value with overloaded operators ++ and --, the compiler generates code for calling operator ++ instead of --.

Minimal complete verifiable example (MCVE):

Tag:operator --(Tag:oper) return Tag:(_:oper - 1);
Tag:operator ++(Tag:oper) return Tag:(_:oper + 1); // the compiler should warn about this operator being unused, not "--"

main()
{
    new Tag:x = Tag:0;
    --x;
    x--;
}
test.pwn(10) : warning 203: symbol is never used: "operator--(Tag:)"

When using the -a option, the following listing for function main() is generated:

proc    ; main
; line 7
; line 8
;$lcl x fffffffc
push.c 0
;$exp
; line 9
push.s fffffffc
;$par
push.c 4
call .++40000002    ; operator++(Tag:)
stor.s.pri fffffffc
move.pri
load.s.pri fffffffc
;$exp
; line a
load.s.pri fffffffc
push.s fffffffc
;$par
push.c 4
call .++40000002    ; operator++(Tag:)
stor.s.pri fffffffc
move.pri
;$exp
stack 4
zero.pri
retn

As can be seen here, the compiler generates code for calling operator ++ instead of -- for both prefix and postfix-form decrement.

Workspace Information:

Daniel-Cortez commented 3 years ago

It seems the reason of this bug is that functions user_inc() and user_dec() (file sc3.c) are empty:

/* These two functions are defined because the functions inc() and dec() in
 * SC4.C have a different prototype than the other code generation functions.
 * The arrays for user-defined functions use the function pointers for
 * identifying what kind of operation is requested; these functions must all
 * have the same prototype. As inc() and dec() are special cases already, it
 * is simplest to add two "do-nothing" functions.
 */
static void user_inc(void) {}
static void user_dec(void) {}

, so in Release and MinSizeRel modes they simply get merged into one function, and because of this, instead of operator --(Tag:) the compiler tries to find and call operator ++(Tag:). Simply adding extra code into either of those functions, e.g.

static void user_inc(void) {}
static void user_dec(void) { dec(NULL); }

prevents this optimization and thus fixes the problem, but I'm pretty sure there might be a better solution for this, preferable the one that doesn't involve adding any extra code at all.

Y-Less commented 3 years ago

That's not good... Hopefully there's a solution that doesn't rely on trying to avoid compiler optimisations, because that's a battle you'll never truly win - it'll undoubtedly pop up again in some other place some other time.

Daniel-Cortez commented 3 years ago

Fixed in #617.