Skip to content
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

Merged
merged 1 commit into from Mar 20, 2019

Conversation

RazvanN7
Copy link
Contributor

@RazvanN7 RazvanN7 commented Mar 19, 2019

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

@dlang-bot
Copy link
Contributor

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 verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the annotated coverage diff directly on GitHub with CodeCov's browser extension
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

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

Auto-close Bugzilla Severity Description
19731 normal auto struct methods whose address is taken don't test invariants

Testing this PR locally

If 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"

@jacob-carlborg
Copy link
Contributor

Does this only apply to structs?

@RazvanN7
Copy link
Contributor Author

@jacob-carlborg No, it also applies to classes, but I haven't figured a solution to that.

@RazvanN7
Copy link
Contributor Author

RazvanN7 commented Mar 19, 2019

Any ideas why the autotester is failing my test with SegFault while circleCi passes? I cannot reproduce the failure locally.

Copy link
Contributor

@thewilsonator thewilsonator left a 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.

@RazvanN7
Copy link
Contributor Author

RazvanN7 commented Mar 19, 2019

Any ideas why the autotester is failing my test with SegFault while circleCi passes? I cannot reproduce the failure locally.

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 ?

@RazvanN7 RazvanN7 force-pushed the Issue_19731 branch 2 times, most recently from 330207e to 9005e32 Compare March 20, 2019 09:15
@RazvanN7
Copy link
Contributor Author

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++)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

foreachDsymbol.

@dlang-bot dlang-bot merged commit 3a298e5 into dlang:master Mar 20, 2019

auto obj7()
{
return this.obj_;
Copy link
Contributor

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...

@dnadlinger
Copy link
Member

@RazvanN7: See @kinke's comment – it seems like this broke the resulting AST in quite a nasty way (assuming this is not LDC-specific, which it doesn't appear to be). Any pointers as to the best fix would be appreciated.

@kinke
Copy link
Contributor

kinke commented May 5, 2019

I gained more insight (analysis performed with LDC and its slightly modified front-end): 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 is 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.

The syntaxCopied testcase's ThisExp.var still points to the variable in the original function, so LDC assumes it is a nested variable and fails to find a matching parent function.

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.

kinke added a commit to kinke/ldc that referenced this pull request May 5, 2019
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.
kinke added a commit to kinke/ldc that referenced this pull request May 5, 2019
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.
@kinke
Copy link
Contributor

kinke commented May 5, 2019

So the questions are

  • Is this just the tip of the ice berg?
  • Why does DMD not suffer from/bail out on this?

@ibuclaw
Copy link
Member

ibuclaw commented May 6, 2019

Why does DMD not suffer from/bail out on this?

DMD has never been too strict on its own codegen AST.

@ibuclaw
Copy link
Member

ibuclaw commented May 6, 2019

Is this just the tip of the ice berg?

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 PASSsemanticX/PASSsemanticXdone unless its parent is also PASSsemanticX (in the middle of running that semantic).

kinke added a commit to kinke/dmd that referenced this pull request May 18, 2019
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).
kinke added a commit to kinke/dmd that referenced this pull request May 18, 2019
See dlang#9467. Be less optimistic, as IMO this approach is likely to cause
issues.
@ibuclaw
Copy link
Member

ibuclaw commented Aug 22, 2019

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.

@ibuclaw
Copy link
Member

ibuclaw commented Aug 22, 2019

And infact, you can reproduce this in dmd by compiling the test with -inline.

@ibuclaw
Copy link
Member

ibuclaw commented Aug 22, 2019

@RazvanN7 - I've reopened the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
7 participants