Skip to content

[SILOptimizer] Don't diagnose infinite recursion if a branch terminates the program #19781

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

Merged

Conversation

harlanhaskins
Copy link
Contributor

@harlanhaskins harlanhaskins commented Oct 8, 2018

(Re-applies commit e94450e, but alters the strategy)

This patch augments the infinite recursion checker to not warn if a
branch terminates, but still warns if a branch calls into something with
@_semantics("programtermination_point"). This way, calling fatalError
doesn't disqualify you for the diagnostic, but calling exit does.

This also removes the warning workaround in the standard library, and
annotates the internal _assertionFailure functions as
programtermination_points, so they get this treatment too.

rdar://45080912

@harlanhaskins harlanhaskins requested a review from gottesmm October 8, 2018 23:16
@harlanhaskins harlanhaskins force-pushed the terminator-2-judgement-day branch 2 times, most recently from 0ee9bea to 9f6164b Compare October 8, 2018 23:19
…es the program

This patch augments the infinite recursion checker to not warn if a
branch terminates, but still warns if a branch calls into something with
@_semantics("programtermination_point"). This way, calling fatalError
doesn't disqualify you for the diagnostic, but calling exit does.

This also removes the warning workaround in the standard library, and
annotates the internal _assertionFailure functions as
programtermination_points, so they get this treatment too.
@harlanhaskins harlanhaskins force-pushed the terminator-2-judgement-day branch from 9f6164b to ed00dbc Compare October 8, 2018 23:21
@harlanhaskins
Copy link
Contributor Author

@swift-ci please test

Copy link
Contributor

@gottesmm gottesmm left a comment

Choose a reason for hiding this comment

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

Looks great. Some questions:

  1. Did you use clang-format? I thought that clang-format formatted the case statements so that they are directly under the switch?
  2. I was thinking about the problem that was run into. Is it possible for us to get tests for that. I am hesitant if it is truly needed since the implementation is so simple.

But functionally, LGTM! I really like where we iterated to with this. = ).

@@ -1061,6 +1061,30 @@ bool TermInst::isFunctionExiting() const {
llvm_unreachable("Unhandled TermKind in switch.");
}

bool TermInst::isProgramTerminating() const {
switch (getTermKind()) {
case TermKind::BranchInst:
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you run this through git-clang-format?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah! Thanks, I will. Xcode's reindent-on-paste indents each case 😢

@harlanhaskins
Copy link
Contributor Author

@gottesmm For posterity, the problem that caused this to revert was that _emptyStringAddressBits could possibly have side effects, but it's only used on i386/arm, which I didn't test when I merged the first PR. Since that function is called when creating the empty string, the call to fatalError() implicitly called it after inlining the default argument initializer. The presence of something with side effects defeated the ARC inertness check, which it turns out was the wrong check for infinite recursion detection anyway.

By checking explicitly for the presence of an apply of something with @_semantics("programtermination_point"), we disregard inertness when looking for infinite recursion.

All that to say that a possible test to ensure we don't regress on this specific bug is:

func mayHaveSideEffects() {}

func x() { // expected-warning {{all paths through this function will call itself}}
  if Bool.random() {
    // execute some side effects
    mayHaveSideEffects()
    fatalError()
  }
  x()
}

And I'll add that test.

@harlanhaskins
Copy link
Contributor Author

@swift-ci please test

@swift-ci
Copy link
Contributor

swift-ci commented Oct 9, 2018

Build failed
Swift Test OS X Platform
Git Sha - ed00dbc

@swift-ci
Copy link
Contributor

swift-ci commented Oct 9, 2018

Build failed
Swift Test Linux Platform
Git Sha - ed00dbc

@harlanhaskins harlanhaskins merged commit 00cc011 into swiftlang:master Oct 9, 2018
modelorganism pushed a commit to modelorganism/swift that referenced this pull request Oct 11, 2018
…es the program (swiftlang#19781)

* [SILOptimizer] Don't diagnose infinite recursion if a branch terminates the program

This patch augments the infinite recursion checker to not warn if a
branch terminates, but still warns if a branch calls into something with
@_semantics("programtermination_point"). This way, calling fatalError
doesn't disqualify you for the diagnostic, but calling exit does.

This also removes the warning workaround in the standard library, and
annotates the internal _assertionFailure functions as
programtermination_points, so they get this treatment too.

* Fix formatting in SILInstructions.cpp

* Re-add missing test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants