HaxeFoundation / HaxeFoundation/haxe

[cpp] Lambda bug with Const type parameter

Open
#12,209 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Haxe
Stars
6.9k
Forks
715
Avg merge
2d 2h
Merged PRs (30d)
11

Description

## INFO
Haxe: `4.3.4`
Target: `cpp`
Platform: `windows`

## TEST CODE

Main.hx

```haxe
package;

@:generic
class BaseCustomType {
var value:String;

public function new() {
value = "BaseCustomType";
}

public function print():Void {
trace(value); // works

var lol = function() {
trace("before");
trace("lol", value);
trace("after");
}

lol(); // does not work (null object reference)
}
}

@:genericBuild(CustomMacro.build())
class CustomType {}

class Main {
public static function main() {
var hello = new CustomType<"Hello, Haxe!">();
hello.print();
}
}

```

CustomMacro.hx

```haxe
package;

#if !macro
class CustomMacro {}
#else
import haxe.macro.Context;
import haxe.macro.Type;
import haxe.macro.Expr;

using haxe.macro.Tools;

class CustomMacro {
static var counter:Int = 0;

public static function build():ComplexType {
var param = switch (Context.getLocalType()) {
case TInst(_, [param]):
param;
default:
throw "CustomMacro can only be used on a type parameter";
}

var s = switch (param) {
case TInst(_.get() => {kind: KExpr(macro $v{(s : String)})}, _):
s;
default:
throw "CustomMacro can only be used on a type parameter with a string literal";
}

var e = switch (param) {
case TInst(_.get() => {kind: KExpr(e)}, _):
e;
default:
throw "CustomMacro can only be used on a type parameter with a string literal";
}

var cls = Context.getLocalClass().get();

var name = cls.name + "_" + counter++;

var baseType:TypePath = {
pack: [],
name: "Main",
sub: "BaseCustomType",
params: [TPExpr(e)]
};

var genCls = macro class $name extends $baseType {
public function new() {
super();
value = $v{s};
}
};
genCls.pos = Context.currentPos();

Context.defineType(genCls);
return Context.getType(name).toComplexType();
}
}
#end

```

## ISSUE
We have `CustomType` which uses `@:genericBuild` to do stuff with the `Const` type parameter.
We also have `BaseCustomType`, with the `@:generic` metadata. Its purpose is to hold the base implementation of the class.

When we have a class with the `@:generic` metadata, it creates two cpp files:
`BaseCustomType__34_Hello_44__32_Haxe_33__34_`
`BaseCustomType_String`

This isn't necessarily an issue, however i noticed that lambdas don't work anymore.
I've tracked it down in the generated cpp code to be an issue with casting `this` to the wrong type.

The cpp code, creates a `_gthis` variable and parses it to the lambda as an argument.

The issue is that inside `BaseCustomType__34_Hello_44__32_Haxe_33__34_obj` it does this:
```cpp
::BaseCustomType_String _gthis = ::hx::ObjectPtr(this);
```

However, it needs to be:
```cpp
::BaseCustomType__34_Hello_44__32_Haxe_33__34_ _gthis = ::hx::ObjectPtr(this);
```

Since it casts it to the wrong type, it leads to a `Null Object Reference` error, when trying to access a member variable inside the lambda

Contributor guide

Open the contributing guide

Research direction

Reproduce the issue using the Main.hx and CustomMacro.hx examples with Haxe 4.3.4 targeting C++ on Windows, then inspect the generated BaseCustomType C++ files. Trace the lambda's _gthis type and verify that accessing value inside the lambda no longer causes a null object reference.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.