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 19731 - auto struct methods whose address is taken don't test invariants #9467
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 fetch digger
dub run digger -- build "master + dmd#9467" |
Does this only apply to structs? |
@jacob-carlborg No, it also applies to classes, but I haven't figured a solution to that. |
Any ideas why the autotester is failing my test with SegFault while circleCi passes? I cannot reproduce the failure locally. |
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 would be nice to convert the loop to use all early returns to reduce nesting.
Got it; it's because of -inline -O; it seems that with these 2 switches the compiler catches null dereferences and outputs an error. Is there a way to tell the test runner to not use -inline and -O ? |
330207e
to
9005e32
Compare
I added the fix for classes. I think this is ready to be merged |
private void reinforceInvariant(AggregateDeclaration ad, Scope* sc) | ||
{ | ||
// for each member | ||
for(int i = 0; i < ad.members.dim; i++) |
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.
foreachDsymbol
.
|
||
auto obj7() | ||
{ | ||
return this.obj_; |
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.
For LDC, the this
VarDeclaration's parent2 isn't the codegen'd Foo.obj7
anymore (so we wrongly assume it's a nested variable). It's another obj7
, so I guess the one from the first semantic pass...
I gained more insight (analysis performed with LDC and its slightly modified front-end): The syntaxCopied testcase's With this (edit: updated) override in ThisExp: override Expression syntaxCopy()
{
auto r = cast(ThisExp) super.syntaxCopy();
// require new semantic (possibly new `var` etc.)
r.type = null;
r.var = null;
return r;
} the testcase works fine. |
expressionSemantic() for a ThisExp doesn't just set its type (and do nothing if it's already set), but may also set the ThisExp.var VarDeclaration. This crucial step was previously skipped after syntaxCopying an already analyzed ThisExp, as a later expressionSemantic() for that copy was a no-op and `var` still pointed to the original one. This fixes runnable/test19731.d, as dlang/dmd#9467 may lead to a syntaxCopy of a sema3'd FuncDeclaration, and that copy replacing the original function. A ThisExp's `var` still pointed to the variable in the original function, so LDC assumed it was a nested variable and failed to find a matching parent function.
expressionSemantic() for a ThisExp doesn't just set its type (and do nothing if it's already set), but may also set the ThisExp.var VarDeclaration. This crucial step was previously skipped after syntaxCopying an already analyzed ThisExp, as a later expressionSemantic() for that copy was a no-op and `var` still pointed to the original one. This fixes runnable/test19731.d, as dlang/dmd#9467 may lead to a syntaxCopy of a sema3'd FuncDeclaration, and that copy replacing the original function. A ThisExp's `var` still pointed to the variable in the original function, so LDC assumed it was a nested variable and failed to find a matching parent function.
So the questions are
|
DMD has never been too strict on its own codegen AST. |
It would appear at a naive glance that TraitsExp is doing something nasty to force complete a decl whose context is only partially done. One litmus test to see how deep the rabbit hole goes would be to replace semanticRun with a getter/setter, and enforce in the setter that a decl cannot be marked |
expressionSemantic() for a ThisExp doesn't just set its type (and do nothing if it's already set), but may also set the ThisExp.var VarDeclaration. This crucial step was previously skipped after syntaxCopying an already analyzed ThisExp, as a later expressionSemantic() for that copy was a no-op and `var` still pointed to the original one, while that variable may have been syntaxCopied too. See the comments in dlang#9467; this is covered by an existing test which happens to pass with DMD (but failed with LDC).
See dlang#9467. Be less optimistic, as IMO this approach is likely to cause issues.
Another regression this has caused, is that now functions are sent to the backend twice. First without the invariant code, and second with invariant code. |
And infact, you can reproduce this in dmd by compiling the test with |
@RazvanN7 - I've reopened the issue. |
Alternative fix to: [1].
When a struct is semantically analyzed, if any member functions (for some reason) have had semantic3 ran on them and the struct has invariants, then the function is reduced to having just semantic ran on it. As things stand, I don't see any other way, as semantic3 for function declarations is a monster function that does tons of things besides solving the return type of a function.
CC @FeepingCreature
[1] #9448