Mercurial > pub > dyncall > dyncall
diff test/callback_plain_c++/test_main.cc @ 557:b36a738c8975
- dyncallback: fix for calling back win/x64 C++ methods returning non-trivial aggregates (thanks Raphael!)
- test/callback_plain_c++:
* added test code for C++ method callbacks returning non-trivial aggregates
* makefile linker command fix (was linking assuming c and not c++)
- test/plain_c++: comments for completeness
author | Tassilo Philipp |
---|---|
date | Sat, 20 Aug 2022 21:04:15 +0200 |
parents | 214c4efc104f |
children | 87b5f5d7af1f |
line wrap: on
line diff
--- a/test/callback_plain_c++/test_main.cc Mon Jul 11 23:17:50 2022 +0200 +++ b/test/callback_plain_c++/test_main.cc Sat Aug 20 21:04:15 2022 +0200 @@ -111,7 +111,7 @@ char cbNonTrivAggrReturnHandler(DCCallback* cb, DCArgs* args, DCValue* result, void* userdata) { - printf("reached callback\n"); + printf("reached callback (for sig \"%s\")\n", *(const char**)userdata); dcbReturnAggr(args, result, NULL); // this sets result->p to the non-triv aggr space allocated by the calling convention *(NonTriv*)result->p = NonTriv(1, 3); // explicit non-copy ctor and assignment operator, so not using NonTriv's statics a and b @@ -119,31 +119,49 @@ } +// class with single vtable entry, used to get the compiler to generate a +// method call; entry is at beginning w/o offset (see plain_c++/test_main.cc +// about potential vtable entry offsets) +struct Dummy { virtual NonTriv f() = 0; }; + + int testNonTrivAggrReturnCallback() { int ret = 1; + const char *sigs[] = { + ")A", // standard call + "_*p)A" // thiscall w/ this-ptr arg (special retval register handling in win/x64 calling conv) + }; + + + for(int i=0; i<sizeof(sigs)/sizeof(sigs[0]); ++i) { - DCCallback* cb; + int is_method = (sigs[i][0] == '_' && sigs[i][1] == '*'); + DCaggr *aggrs[1] = { NULL }; // one non-triv aggr - cb = dcbNewCallback2(")A", &cbNonTrivAggrReturnHandler, NULL, aggrs); + DCCallback* cb = dcbNewCallback2(sigs[i], &cbNonTrivAggrReturnHandler, sigs+i, aggrs); - NonTriv result = ((NonTriv(*)())cb)(); // potential copy elision on construction + DCpointer fakeClass[sizeof(Dummy)/sizeof(sizeof(DCpointer))]; + fakeClass[0] = &cb; // write method ptr f + + // potential copy elision on construction + NonTriv result = is_method ? ((Dummy*)&fakeClass)->f() : ((NonTriv(*)())cb)(); int a = NonTriv::a-1; int b = NonTriv::b-1; - printf("successfully returned from callback 1/2\n"); + printf("successfully returned from callback 1/2 of \"%s\"\n", sigs[i]); printf("retval w/ potential retval optimization and copy-init (should be %d %d for init or %d %d for copy, both allowed by C++): %d %d\n", 1, 3, a, b, result.i, result.j); ret = ((result.i == 1 && result.j == 3) || (result.i == a && result.j == b)) && ret; - // avoid copy elision on construction - result.i = result.j = -77; - result = ((NonTriv(*)())cb)(); // potential copy elision + // avoid copy elision on construction + result.i = result.j = -77; + result = is_method ? ((Dummy*)&fakeClass)->f() : ((NonTriv(*)())cb)(); // potential copy elision a = NonTriv::a-1; b = NonTriv::b-1; - printf("successfully returned from callback 2/2\n"); + printf("successfully returned from callback 2/2 of \"%s\"\n", sigs[i]); printf("retval w/ potential retval optimization and copy-init (should be %d %d for init or %d %d for copy, both allowed by C++): %d %d\n", 1, 3, a, b, result.i, result.j); dcbFreeCallback(cb);