Issue 16527 - extern( C++ ) Win64 build - return struct by value is broken
Summary: extern( C++ ) Win64 build - return struct by value is broken
Status: RESOLVED WORKSFORME
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: x86_64 Windows
: P1 blocker
Assignee: No Owner
URL:
Keywords: C++
Depends on:
Blocks:
 
Reported: 2016-09-23 14:48 UTC by Ethan Watson
Modified: 2018-05-14 14:13 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Ethan Watson 2016-09-23 14:48:18 UTC
DMD 2.071.2, Windows, 64-bit output.

The this pointer should be always stored in RCX, but the functions I'm using where structs are being returned by value switch the return address from RDX with RCX.

While I'm actually using raw C++ functions through Binderoo, this is actually quite reproducible with D code that extern( C++ )'s its functions.

Marking as blocker as there's a ridiculous number of functions we bind to that return structs by value that are just unusable.

Code as follows:

module thismodule;

import std.stdio;
import std.conv;

align( 16 ) struct SomeCommonStruct
{
	float valA = 0;
	float valB = 0;
	float valC = 0;
	float valD = 0;
}

struct SomeObject
{
	void doAThing()
	{
		SomeWrapper aWrapper;

		SomeCommonStruct structThing = aWrapper.callme( &aWrapper );

		writeln( to!string( structThing.valD ) );
	}

}

extern( C++ ) struct SomeWrapper
{
	SomeCommonStruct giveMeACommonStruct( SomeObject* pObject )
	{
		return structeroo;
	}

	SomeCommonStruct structeroo = SomeCommonStruct( 1, 0, 3, 4 );

	alias FnType = extern( C++ ) SomeCommonStruct function( SomeWrapper* );

	__gshared extern( C++ ) SomeCommonStruct function( SomeWrapper* ) callme;
}

int main(string[] argv)
{
	SomeWrapper.callme = cast( SomeWrapper.FnType )cast(void*)&SomeWrapper.giveMeACommonStruct;

	SomeObject someObject;
	someObject.doAThing();

	return 0;
}

Expected: function SomeObject.doAThing writes the value "4" to stdout
Actual: function SomeObject.doAThing writes rubbish to stdout
Comment 1 kinke 2016-09-24 08:47:01 UTC
We have a special case for this in LDC. MSVC passes `this` before `sret`, unlike most other ABIs.
Comment 2 Sprink 2017-01-16 05:15:21 UTC
The problem is that there's no way to properly model a pointer to a member function to C++ from D. You can't use a delegate as it isn't supported with extern(C++). So there's no way for it to know that the parameter you are passing is actually a "this". Taking the address of a member function without an object is also broken (#3720).
Comment 3 Ethan Watson 2018-05-14 14:13:32 UTC
Looks like this issue was fixed somewhere along the line. Example code works just fine on run.dlang.org, and the interop code I was working on for C# that was returning structs was also working just fine on DMD 2.078. No idea when exactly this would have been fixed, but it certainly Works For Me! now.