HaxeFoundation / HaxeFoundation/haxe

3.4-rc.1 cpp variable folding (regression)

Open
#5,891 15 comments 0 reactions 1 assignee Claimed by @hughsando View on GitHub
platform-cpp
Dominant language
Haxe
Stars
6.9k
Forks
715
Avg merge
2d 2h
Merged PRs (30d)
11

Description

This is a tricky one to pin down, I'm going to describe it first to gather insight.

Haxe `3.4.0 (git build development @ 57948c9)`
hxcpp git `b2a1efc46e8dee75e630195646cc11da4964143c`

This code worked on 3.2.1 as expected.

In this extern cpp library for ENet, there is [some simple code](https://github.com/snowkit/linc_enet/blob/master/test/Client.hx#L46-L48):

_(ignore the typo on `adress`)_
```haxe
var peer = event.peer;
var adress = peer.address;
var host = adress.host;
```

This code is typed correctly, to our externs ENetPeer, ENetAddress.
**This is correct**, and works as intended. The cpp generated code looks like this:

```c++
HXLINE( 46) ::cpp::Reference peer1 = event->peer;
HXLINE( 47) HX_VARI( ::cpp::Struct,adress) = peer1->address;
HXLINE( 48) HX_VARI( int,host) = adress->host;
```

However, in another usage of the exact same library, the almost exact same code the same variables become condensed:

```haxe
var _peer = _event.peer;
var _address = _peer.address;
var _host = _address.host;
```

In this case the c++ generated is different, folding the access:

```c++
HXLINE( 126) HX_VARI( int,_host) = _event->peer->address->host;
```

**This is broken**, because the access pattern changes the semantics.
In this case it is reading the variable directly i.e the peer is no longer cast to the correct type, therefore `address` is actually referring to the _native_ ENet type and not the haxe extern type. This leads to a c++ compiler error:

```
error: member reference type 'ENetAddress' (aka '_ENetAddress') is not a pointer; did you mean to use '.'?
HXLINE( 126) HX_VARI( int,_host) = _event->peer->address->host;
```

The code is almost the same (see below for the code as it was a local repo), and I have tried reducing the difference between the two functions to nothing yet this second instance compiles differently. I have also checked there are no strange defines or compiler flags difference. I can't even get the simple test case to reproduce the incorrect output no matter what I try.

The dump does end up different:

The correct one:
```
[Var peer1(17886):::cpp::Reference]
[Field:::cpp::Reference]
[Local event(17863):::cpp::Struct]
[FInstance:::cpp::Reference]
::ENetEvent
peer
[Var adress(17887):::cpp::Struct]
[Field:::cpp::Struct]
[Local peer1(17886):::cpp::Reference]
[FInstance:::cpp::Struct]
::ENetPeer
address
[Var host(17888):cpp.Int32]
[Field:cpp.Int32]
[Local adress(17887):::cpp::Struct]
[FInstance:cpp.Int32]
::ENetAddress
host
```

The incorrect one:
```
[Var _host(38857):cpp.Int32]
[Field:cpp.Int32]
[Field:::cpp::Struct]
[Field:::cpp::Reference]
[Local _event(38852):::cpp::Struct]
[FInstance:::cpp::Reference]
::ENetEvent
peer
[FInstance:::cpp::Struct]
::ENetPeer
address
[FInstance:cpp.Int32]
::ENetAddress
host
```

The code in question:
```haxe

function tick() {

if(state == cs_disconnected) {
return;
}

var _event: ENetEvent = null;
var _status:Int = ENet.host_service(client, cast _event, 0);

if(_status > 0) {

var _peer = _event.peer;
var _address = _peer.address;
var _host = _address.host;

switch(_event.type) {

case ENetEventType.ENET_EVENT_TYPE_CONNECT:
log(' connected to server $_host');
state = cs_connected;
if(onconnected != null) onconnected();

case ENetEventType.ENET_EVENT_TYPE_RECEIVE:

var _json_string = _event.packet.getDataBytes().toString();
var _message:ClientMessage = haxe.Json.parse(_json_string);

if(onmessage != null) onmessage(_message);

ENet.packet_destroy(_event.packet);

case ENetEventType.ENET_EVENT_TYPE_DISCONNECT:
// var _d = event.peer.data
log(' disconnected from server $_host');
if(ondisconnected != null) ondisconnected();

state = cs_disconnected;

default:
log('ignored event type: ${_event.type}');

} //switch event type

} //_status

} //tick
```

Any thoughts @hughsando @Simn on narrowing this down?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.