-
-
Notifications
You must be signed in to change notification settings - Fork 672
Fix Issue 21288 & 10886 - incorrect this pointer #14969
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
Conversation
|
Thanks for your pull request and interest in making D better, @RazvanN7! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla references
Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "stable + dmd#14969" |
| if (!requiredAd) | ||
| return false; | ||
|
|
||
| if (thisAd == requiredAd) |
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.
wouldn't just is be enough here ?
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.
Indeed, is would be preferred since we want to compare the pointers, but AST nodes do not define opEquals so we are fine with the default opEquals of object. Indeed, it would be slightly faster cause we are bypassing the the call to object.opEquals, but I doubt that this makes a performance difference in the release, inlined binary.
Long story-short: both is and == are fine in this case.
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.
I dont see the problem with is, for the comment about coverage you are protective, i.e "in case of" but for this one you are not. "In case of" comparison overload would be used (at some point, even if unlikey), is is better.
dkorpel
left a comment
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.
My gut reaction to the diff was "this doesn't look right", but after reading it more carefully and reviewing it, it does look like a valid code change. Perhaps the documentation on haveSameThis could be clarified to make it easier to understand what's going on.
| @@ -0,0 +1,10 @@ | |||
| struct S1(T...) { | |||
| auto fun() { | |||
| static assert(__traits(compiles, &T[0])); | |||
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.
This compiles now, but does the resulting delegate have the right this parameter?
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.
But the result is not a delegate, it's a function, so there is no this pointer.
| * `true` if outerFunc and calledFunc may use the same `this` pointer. | ||
| * `false` otherwise. | ||
| */ | ||
| private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc) |
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.
This function doesn't look right. The logic in the function is surprisingly complex (many branches). I would expect haveSameThis to be commutative and take two arbitrary functions, but the names outerFunc and calledFunc suggest there are restrictions to the parameters which aren't documented.
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.
Initially, I thought the fix is easy. I thought it would suffice to make sure that the this of the function containing the call and the this of the function being called are the same, however that does not cut it for derived member functions. Later on, I noticed that for nested functions there is some extra engineering done to get the right this. That's when I ended up with this function. I suspect that there are other places where this function might be used.
I don't think it can be made any simpler than that, but I am confident that what is in there at this point is correct.
| /* | ||
| * Check whether `outerFunc` and `calledFunc` have the same `this`. | ||
| * If `calledFunc` is the member of a base class of the class that contains | ||
| * `outerFunc` we consider that they have the same this. |
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.
The example makes it unclear what "have same this" means, it sounds more like "have covariant typeof(this)"
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.
Well, I followed the existing naming pattern after getRightThis.
| if (e.e1.op == EXP.error) | ||
| return setError(); |
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.
Why is this removed?
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.
Because it was added to fix a symptom of the bug this PR is fixing. Take a look at: #10123
|
@dkorpel I added some clarifications. |
|
@dkorpel Thanks for the review. |
|
This commit has introduced a regression, see https://issues.dlang.org/show_bug.cgi?id=24013. |
|
I guess this also caused regression https://issues.dlang.org/show_bug.cgi?id=24109. |
| * `this` can be prepended to `fun`. When `gun` is called (it will result | ||
| * in an error, but that is not relevant here), which is a member of `X`, | ||
| * no `this` is needed because the outer function does not have the same | ||
| * `this` as `gun`. |
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.
But it will fail anyway because X.gun() does not supply a this to gun.
It seems that when a function is called the, if it requires a context pointer, the compiler simply rewrites it to
this.fcalleven though the function that is being call sometimes explicitly provides it's aggregate. This leads to bogus messages and also it makes it impossible to take the address of such functions if inside a this context.I am fixing this by requiring that the this pointers of the called function and the outer aggregate match.