-
-
Notifications
You must be signed in to change notification settings - Fork 594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix Issue 7925 - extern(C++) delegates #13217
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
#include <stdarg.h> | ||
#include <assert.h> | ||
|
||
class C1 | ||
{ | ||
public: | ||
virtual ~C1(); | ||
|
||
int i; | ||
|
||
int f0(); | ||
int f1(int a); | ||
int f2(int a, int b); | ||
virtual int f3(int a, int b); | ||
int f4(int a, ...); | ||
}; | ||
|
||
C1::~C1() | ||
{ | ||
} | ||
|
||
int C1::f0() | ||
{ | ||
return i; | ||
} | ||
|
||
int C1::f1(int a) | ||
{ | ||
return i + a; | ||
} | ||
|
||
int C1::f2(int a, int b) | ||
{ | ||
return i + a + b; | ||
} | ||
|
||
int C1::f3(int a, int b) | ||
{ | ||
return i + a + b; | ||
} | ||
|
||
int C1::f4(int a, ...) | ||
{ | ||
int r = i + a; | ||
int last = a; | ||
|
||
va_list argp; | ||
va_start(argp, a); | ||
while (last) | ||
{ | ||
last = va_arg(argp, int); | ||
r += last; | ||
} | ||
va_end(argp); | ||
return r; | ||
} | ||
|
||
C1 *createC1() | ||
{ | ||
return new C1(); | ||
} | ||
|
||
class C2 | ||
{ | ||
public: | ||
virtual ~C2(); | ||
|
||
int i; | ||
|
||
int f0(); | ||
int f1(int a); | ||
int f2(int a, int b); | ||
virtual int f3(int a, int b); | ||
int f4(int a, ...); | ||
}; | ||
|
||
C2 *createC2(); | ||
|
||
void runCPPTests() | ||
{ | ||
C2 *c2 = createC2(); | ||
c2->i = 100; | ||
assert(c2->f0() == 100); | ||
assert(c2->f1(1) == 101); | ||
assert(c2->f2(20, 3) == 123); | ||
assert(c2->f3(20, 3) == 123); | ||
assert(c2->f4(20, 3, 0) == 123); | ||
|
||
int (C2::*fp0)() = &C2::f0; | ||
int (C2::*fp1)(int) = &C2::f1; | ||
int (C2::*fp2)(int, int) = &C2::f2; | ||
int (C2::*fp3)(int, int) = &C2::f3; | ||
#ifndef __DMC__ | ||
int (C2::*fp4)(int, ...) = &C2::f4; | ||
#endif | ||
assert((c2->*(fp0))() == 100); | ||
assert((c2->*(fp1))(1) == 101); | ||
assert((c2->*(fp2))(20, 3) == 123); | ||
assert((c2->*(fp3))(20, 3) == 123); | ||
#ifndef __DMC__ | ||
assert((c2->*(fp4))(20, 3, 0) == 123); | ||
#endif | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
// EXTRA_CPP_SOURCES: cpp7925.cpp | ||
import core.vararg; | ||
|
||
extern(C++) class C1 | ||
{ | ||
public: | ||
~this(); | ||
|
||
int i; | ||
|
||
final int f0(); | ||
final int f1(int a); | ||
final int f2(int a, int b); | ||
int f3(int a, int b); | ||
final int f4(int a, ...); | ||
}; | ||
|
||
extern(C++) C1 createC1(); | ||
|
||
extern(C++) class C2 | ||
{ | ||
public: | ||
~this() | ||
{ | ||
} | ||
|
||
int i; | ||
|
||
final int f0() | ||
{ | ||
return i; | ||
} | ||
|
||
final int f1(int a) | ||
{ | ||
return i + a; | ||
} | ||
|
||
final int f2(int a, int b) | ||
{ | ||
return i + a + b; | ||
} | ||
|
||
int f3(int a, int b) | ||
{ | ||
return i + a + b; | ||
} | ||
|
||
final int f4(int a, ...) | ||
{ | ||
int r = i + a; | ||
int last = a; | ||
|
||
va_list argp; | ||
va_start(argp, a); | ||
while (last) | ||
{ | ||
last = va_arg!int(argp); | ||
r += last; | ||
} | ||
va_end(argp); | ||
return r; | ||
} | ||
}; | ||
|
||
extern(C++) C2 createC2() | ||
{ | ||
return new C2; | ||
} | ||
|
||
auto callMember(alias F, Params...)(__traits(parent, F) obj, Params params) | ||
{ | ||
static if(__traits(getFunctionVariadicStyle, F) == "stdarg") | ||
enum varargSuffix = ", ..."; | ||
else | ||
enum varargSuffix = ""; | ||
|
||
static if(is(typeof(&F) R == return) && is(typeof(F) P == __parameters)) | ||
mixin("extern(" ~ __traits(getLinkage, F) ~ ") R delegate(P" ~ varargSuffix ~ ") dg;"); | ||
dg.funcptr = &F; | ||
dg.ptr = cast(void*)obj; | ||
return dg(params); | ||
} | ||
|
||
extern(C++) void runCPPTests(); | ||
|
||
void main() | ||
{ | ||
C1 c1 = createC1(); | ||
c1.i = 100; | ||
assert(c1.f0() == 100); | ||
assert(c1.f1(1) == 101); | ||
assert(c1.f2(20, 3) == 123); | ||
assert(c1.f3(20, 3) == 123); | ||
assert(c1.f4(20, 3, 0) == 123); | ||
|
||
auto dg0 = &c1.f0; | ||
auto dg1 = &c1.f1; | ||
auto dg2 = &c1.f2; | ||
auto dg3 = &c1.f3; | ||
auto dg4 = &c1.f4; | ||
assert(dg0() == 100); | ||
assert(dg1(1) == 101); | ||
assert(dg2(20, 3) == 123); | ||
assert(dg3(20, 3) == 123); | ||
assert(dg4(20, 3, 0) == 123); | ||
|
||
assert(callMember!(C1.f0)(c1) == 100); | ||
assert(callMember!(C1.f1)(c1, 1) == 101); | ||
assert(callMember!(C1.f2)(c1, 20, 3) == 123); | ||
assert(callMember!(C1.f3)(c1, 20, 3) == 123); | ||
assert(callMember!(C1.f4)(c1, 20, 3, 0) == 123); | ||
|
||
int i; | ||
extern(C++) void delegate() lamdba1 = () { | ||
i = 5; | ||
}; | ||
lamdba1(); | ||
assert(i == 5); | ||
|
||
extern(C++) int function(int, int) lamdba2 = (int a, int b) { | ||
return a + b; | ||
}; | ||
assert(lamdba2(3, 4) == 7); | ||
|
||
extern(C++) void delegate(int, ...) lamdba3 = (int a, ...) { | ||
i = a; | ||
int last = a; | ||
|
||
va_list argp; | ||
va_start(argp, a); | ||
while (last) | ||
{ | ||
last = va_arg!int(argp); | ||
i += last; | ||
} | ||
va_end(argp); | ||
}; | ||
lamdba3(1000, 200, 30, 4, 0); | ||
assert(i == 1234); | ||
|
||
runCPPTests(); | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks to me like totym() is in the wrong here, not the caller.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
totym() does not know, that the function is used in a delegate, because the argument tf contains the type of funcptr and not the whole delegate. TypeFunction does not seem to have information about the hidden this pointer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An alternative implementation would be to add a flag to TypeFunction, which marks functions with hidden this pointer. Function tytym could then choose the calling convention based on that flag. The flag could also be used to fix https://issues.dlang.org/show_bug.cgi?id=3720 and https://issues.dlang.org/show_bug.cgi?id=17080, but it would be a bigger change and affect more code. You would probably also need a new syntax for function types with hidden this pointer and a trait for getting the flag.