Skip to content

[SILOptimizer] Fixes the ValueDefUseWalker to handle potential unchecked_ref_cast between optional and non-optional class types. #79872

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

WeZZard
Copy link
Contributor

@WeZZard WeZZard commented Mar 9, 2025

The unchecked_ref_cast is designed to be able to cast between Optional<ClassType> and ClassType. We need to handle these cases by checking if the type is optional and adjust the path accordingly.

The absence of this process causes the escape analysis for the operand of the load instruction returns non-escaping if there is a unchecked_ref_cast casting from an optional class type to a non-optional class type. Since this the implicit optional-wrapping does not reflect on the path.

This further makes the redundant load elimination pass to eliminate this load though there is a function with side-effects applied right before the load instruction. Since the function apply effect computation in the alias analysis only returns the effects of the function itself if the operand of the load instruction is not escaped.

@WeZZard
Copy link
Contributor Author

WeZZard commented Mar 9, 2025

Relative issue: #79871
My blogpost explained this issue and the fix solution (may be tedious): https://wezzard.com/post/2025/03/when-the-swift-compiler-deleted-code-in-stdlib-9067

@WeZZard WeZZard changed the base branch from main to release/6.1 March 9, 2025 15:51
@WeZZard WeZZard requested a review from a team as a code owner March 9, 2025 15:51
@WeZZard WeZZard force-pushed the bugfix/unchecked-ref-casting-with-optional-any-object branch from 2c5219f to 21757d0 Compare March 9, 2025 15:52
@Kyle-Ye
Copy link
Contributor

Kyle-Ye commented Mar 10, 2025

@swift-ci please test

…ked_ref_cast between optional and non-optional class types.

The `unchecked_ref_cast` is designed to be able to cast between
`Optional<ClassType>` and `ClassType`. We need to handle these cases by
checking if the type is optional and adjust the path accordingly.
@WeZZard WeZZard force-pushed the bugfix/unchecked-ref-casting-with-optional-any-object branch from 21757d0 to 35f82ba Compare March 10, 2025 12:13
@WeZZard WeZZard changed the base branch from release/6.1 to main March 10, 2025 12:14
@WeZZard
Copy link
Contributor Author

WeZZard commented Mar 10, 2025

Hi, folks. I've just learned that the practice of submitting pull requests in the Swift repository is to merge to the main branch instead of a specific releasing branch. I've updated the targeting branch of the PR and fixed a build issue introduced in the tidying up of the commit history. Could anyone help to trigger the @swift-ci to test my commit?

@jamieQ
Copy link
Contributor

jamieQ commented Mar 10, 2025

@swift-ci please test

Copy link
Contributor

@eeckstein eeckstein left a comment

Choose a reason for hiding this comment

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

Thanks for fixing this!

Copy link
Contributor

@eeckstein eeckstein left a comment

Choose a reason for hiding this comment

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

Thanks, lgtm!

@eeckstein
Copy link
Contributor

@swift-ci test

@WeZZard
Copy link
Contributor Author

WeZZard commented Mar 11, 2025

Hi folks! The tests have completed. I think it's time to complete the code review. Do you have any further advice for this pull request?

Plus, since the reviewers list is incredibly long, I wanna make sure that if this pull request really need to involve so much reviewers? Or we just need to involve those reviewers with the shield icon? Reviewers without the shield icon might be mis-involved because I was originally base with release/6.1 but targeted to the main branch. Now the base and the target branch are both fixed to the main branch and matched.

@ahoppen ahoppen removed their request for review March 11, 2025 15:15
@eeckstein
Copy link
Contributor

Or we just need to involve those reviewers with the shield icon?

It's fine if a single reviewer (who understands the code) gives her/his thumbs up.
But it's always a good idea to add a few reviewers in case anyone else wants to take a look.

@eeckstein eeckstein merged commit 19c51e2 into swiftlang:main Mar 11, 2025
5 checks passed
beccadax added a commit to beccadax/swift that referenced this pull request Apr 5, 2025
When a C enum has multiple constants with the same value, ClangImporter selects one of them to import as an `EnumElementDecl` and imports the others as `VarDecl` “aliases” of that one. This helps preserve the invariant that each case of an enum has a unique raw value and is distinct for exhaustiveness checking.

However, a bug in that logic could sometimes cause the canonical case to be imported *twice*—once as an `EnumElementDecl` and again as a `VarDecl` alias. In this situation, the `EnumElementDecl` was not added to the enum’s member list, resulting in a malformed AST. This bug has apparently been present since early 2017 (!), but it seems to have been harmless until recently, when the `ComputeSideEffects` SIL pass recently became sensitive to it (probably because of either swiftlang#79872 or swiftlang#80263).

Correct this problem by modifying the memoization logic to retrieve the canonical case’s clang-side constant so the subsequent check will succeed. Additionally change a variable name and add comments to help clarify this code for future maintainers.

In lieu of adding new unit tests, this commit adds a (slightly expensive) conditional assertion to catch this kind of AST malformation. There are actually about twenty tests that will fail with just the assertion and not the fix, but I’ve updated one of them to enable the assertion even in release mode.

Fixes rdar://148213237. Followup to swiftlang#80487, which added related assertions to the SIL layer.
beccadax added a commit to beccadax/swift that referenced this pull request Apr 11, 2025
When a C enum has multiple constants with the same value, ClangImporter selects one of them to import as an `EnumElementDecl` and imports the others as `VarDecl` “aliases” of that one. This helps preserve the invariant that each case of an enum has a unique raw value and is distinct for exhaustiveness checking.

However, a bug in that logic could sometimes cause the canonical case to be imported *twice*—once as an `EnumElementDecl` and again as a `VarDecl` alias. In this situation, the `EnumElementDecl` was not added to the enum’s member list, resulting in a malformed AST. This bug has apparently been present since early 2017 (!), but it seems to have been harmless until recently, when the `ComputeSideEffects` SIL pass recently became sensitive to it (probably because of either swiftlang#79872 or swiftlang#80263).

Correct this problem by modifying the memoization logic to retrieve the canonical case’s clang-side constant so the subsequent check will succeed. Additionally change a variable name and add comments to help clarify this code for future maintainers.

In lieu of adding new unit tests, this commit adds a (slightly expensive) conditional assertion to catch this kind of AST malformation. There are actually about twenty tests that will fail with just the assertion and not the fix, but I’ve updated one of them to enable the assertion even in release mode.

Fixes rdar://148213237. Followup to swiftlang#80487, which added related assertions to the SIL layer.
beccadax added a commit to beccadax/swift that referenced this pull request Apr 15, 2025
When a C enum has multiple constants with the same value, ClangImporter selects one of them to import as an `EnumElementDecl` and imports the others as `VarDecl` “aliases” of that one. This helps preserve the invariant that each case of an enum has a unique raw value and is distinct for exhaustiveness checking.

However, a bug in that logic could sometimes cause the canonical case to be imported *twice*—once as an `EnumElementDecl` and again as a `VarDecl` alias. In this situation, the `EnumElementDecl` was not added to the enum’s member list, resulting in a malformed AST. This bug has apparently been present since early 2017 (!), but it seems to have been harmless until recently, when the `ComputeSideEffects` SIL pass recently became sensitive to it (probably because of either swiftlang#79872 or swiftlang#80263).

Correct this problem by modifying the memoization logic to retrieve the canonical case’s clang-side constant so the subsequent check will succeed. Additionally change a variable name and add comments to help clarify this code for future maintainers.

In lieu of adding new unit tests, this commit adds a (slightly expensive) conditional assertion to catch this kind of AST malformation. There are actually about twenty tests that will fail with just the assertion and not the fix, but I’ve updated one of them to enable the assertion even in release mode.

Fixes rdar://148213237. Followup to swiftlang#80487, which added related assertions to the SIL layer.
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