Skip to content

Separate clangimporter errors #6864

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

adrian-prantl
Copy link

@adrian-prantl adrian-prantl commented May 16, 2023

SwiftASTContext resets the state of the DiagnosticConsumer after each
import to make failed module imports non-fatal, however, the internal
state of the DiagnosticEngine in Swift's embedded Clang compiler does
not reset when encountering a fatal error. By storing Clang
diagnostics separately, these errors can be surfaces when an
expression fails to IRGen (which is usually when these fatal Clang
diagnostics turn into an unrecoverable problem).

rdar://108557254

@adrian-prantl
Copy link
Author

@swift-ci test

@adrian-prantl adrian-prantl force-pushed the separate-clangimporter-errors branch from f5dfc31 to f619b5f Compare May 17, 2023 20:17
@adrian-prantl
Copy link
Author

@swift-ci test

2 similar comments
@adrian-prantl
Copy link
Author

@swift-ci test

@adrian-prantl
Copy link
Author

@swift-ci test

@adrian-prantl
Copy link
Author

Introduce a "transactional" diagnostic consumer.

Swift compiler and ClangImporter and LLDB operations can produce
diagnostics, which are stored in StoringDiagnosticConsumer. Operations
such as expression evaluation of module imports may produce multiple
non-fatal error diagnostics. Prior to this patch, the expression
parser would clear the diagnostic consumer before running. This had
the unwanted side-effect of sometimes clearing out unreported earlier
diagnostics.

This patch introduces SwiftASTContext::forkDiagnosticConsumer() which
returns an RAII object that behaves like a diagnostic consumer, can
tell whether diagnostics where produced during its lifetime, and
resets the StoringDiagnosticConsumer to its previous state upon
destruction. This way

  • unreported diagnostics don't get cleared by the expression parser
  • the expression parser has precise access to only the diagnostics it produced
  • while still being able to report persistent errors
    (such as clang import failures) that happened before the expression
    parser started.

I'm not happy by the amount of code needed to make this work, or the
specific implementation, but at least the interface provided to the
outside is nice and clean.

@adrian-prantl adrian-prantl requested a review from bulbazord May 19, 2023 22:17
@adrian-prantl
Copy link
Author

@swift-ci test

@adrian-prantl
Copy link
Author

@swift-ci test windows

@adrian-prantl adrian-prantl force-pushed the separate-clangimporter-errors branch from d11204f to a300454 Compare May 24, 2023 21:08
@adrian-prantl
Copy link
Author

@swift-ci test

Copy link

@bulbazord bulbazord left a comment

Choose a reason for hiding this comment

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

Haven't looked at all of SwiftASTContext yet but the other stuff looks ok I think.

if (expr_diagnostics->HasErrors() ||
m_swift_ast_ctx.HasClangImporterErrors()) {
diagnostic_manager.PutString(eDiagnosticSeverityRemark,
"couldn't IRGen expression");

Choose a reason for hiding this comment

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

Are these messages meant to be seen by end users? If so, IRGen as a term is pretty specific to clang, swift, and llvm... maybe we can say something a little more user friendly like:

Failed to compile expression: IR generation failure

Copy link
Author

Choose a reason for hiding this comment

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

That's a valid concern! Note that this is just one remark in a longer error. For example, the test in lang/swift/clangimporter/clang_errorhandling produces:

error: expression failed to parse:
couldn't IRGen expression
error: /Volumes/Data/swift-5.9/llvm-project/lldb/test/API/lang/swift/clangimporter/clang_errorhandling/bridging-header.h:2:1: error: unknown type name 'i'
i am a syntax error
^

error: /Volumes/Data/swift-5.9/llvm-project/lldb/test/API/lang/swift/clangimporter/clang_errorhandling/bridging-header.h:2:5: error: expected ';' after top level declarator
i am a syntax error
    ^

error: failed to import bridging header '/Volumes/Data/swift-5.9/llvm-project/lldb/test/API/lang/swift/clangimporter/clang_errorhandling/bridging-header.h'

as the full error message.

Copy link
Author

Choose a reason for hiding this comment

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

The IRGen remark is really mostly there for LLDB developers to understand at what point the expression failed to help with troubleshooting.

Copy link
Author

Choose a reason for hiding this comment

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

With this in mind — any suggestions for how to improve the error message?

@adrian-prantl adrian-prantl force-pushed the separate-clangimporter-errors branch 2 times, most recently from 3c23fdd to f79bcc7 Compare May 25, 2023 17:59
@adrian-prantl
Copy link
Author

@swift-ci test

1 similar comment
@adrian-prantl
Copy link
Author

@swift-ci test

@adrian-prantl
Copy link
Author

@swift-ci test windows

Copy link

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

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

I didn't re-review everything but I see my concerns were addressed to LGTM.

SwiftASTContext resets the state of the DiagnosticConsumer after each
import to make failed module imports non-fatal, however, the internal
state of the DiagnosticEngine in Swift's embedded Clang compiler does
not reset when encountering a fatal error. By storing Clang
diagnostics separately, these errors can be surfaces when an
expression fails to IRGen (which is usually when these fatal Clang
diagnostics turn into an unrecoverable problem).

rdar://108557254
Swift compiler and ClangImporter and LLDB operations can produce
diagnostics, which are stored in StoringDiagnosticConsumer. Operations
such as expression evaluation of module imports may produce multiple
non-fatal error diagnostics.  Prior to this patch, the expression
parser would clear the diagnostic consumer before running. This had
the unwanted side-effect of sometimes clearing out unreported earlier
diagnostics.

This patch introduces SwiftASTContext::forkDiagnosticConsumer() which
returns an RAII object that behaves like a diagnostic consumer, can
tell whether diagnostics where produced during its lifetime, and
resets the StoringDiagnosticConsumer to its previous state upon
destruction. This way

- unreported diagnostics don't get cleared by the expression parser
- the expression parser has precise access to only the diagnostics it produced
- while still being able to report persistent errors
  (such as clang import failures) that happened before the expression
  parser started.

I'm not happy by the amount of code needed to make this work, or the
specific implementation, but at least the interface provided to the
outside is nice and clean.
@adrian-prantl adrian-prantl force-pushed the separate-clangimporter-errors branch from c7a7056 to a2052d2 Compare May 31, 2023 21:55
@adrian-prantl
Copy link
Author

@swift-ci test

@adrian-prantl
Copy link
Author

@swift-ci test windows

@adrian-prantl adrian-prantl merged commit ce97507 into swiftlang:swift/release/5.9 May 31, 2023
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.

4 participants