HaxeFoundation / HaxeFoundation/haxe
3.4-rc.1 cpp variable folding (regression)
- 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
Assessment
This issue has not been assessed yet.