HaxeFoundation / haxe

Haxe - The Cross-Platform Toolkit
https://haxe.org
6.03k stars 648 forks source link

[cpp] Abstract class functions with default values are broken #11666

Closed Aidan63 closed 1 month ago

Aidan63 commented 1 month ago

Calling a function on an abstract class which has default values has seemingly never worked properly, I just spotted this as it generates invalid C++ when compiled with -D sciptable, but upon closer inspection they don't actually worked for non cppia enabled compiles either.

abstract class Foo {
    abstract public function foo(v:Int = 0):Void;
}

class ConcreteFoo extends Foo {
    public function new() {}

    public function foo(v:Int = 0) {
        trace(v);
    }
}

function main() {
    final o = new ConcreteFoo();

    o.foo(7);

    (o : Foo).foo(12);
}

The way they're broken is a bit hard to catch, in the above example you'd expect 7 then 12 to be traced, but you only see 7 and then the program exits (no crash / exception, a graceful exit). Invoking these functions on the concrete type is fine, but trying to use the abstract base is where the issues come into play. The generated C++ class from the abstract class generates virtual foo(int v) {} where as the concrete class gets the correct virtual foo(::hx::Null<int> __o_v), but since these are different signatures they're different functions, so calling foo on the base invokes that empty function...hence no crash.

Issue seems to be the abstract class path calls ctx_arg with no default expression so it doesn't think the abstract version has a default value, I've got a WIP fix which checks for the value meta which seems to be where abstract classes store default argument expressions.