Skip to content

[cxx-interop] Fix assertion failure from unavailable typedef + enum pattern #81625

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
merged 6 commits into from
May 22, 2025

Conversation

j-hui
Copy link
Contributor

@j-hui j-hui commented May 19, 2025

The NS_OPTIONS macro sometimes uses a pattern where it loosely
associates a typedef with an anonymous enum via a shared underlying
integer type (emphasis on "loosely"). The typedef is marked as
unavailable in Swift so as to not cause name ambiguity when we associate
the anonymous enum with said typedef. We use unavailability as
a heuristic during the import process, but that conflates NS_OPTIONS
with NS_ENUMs that can be marked as unavailable for entirely unrelated
reasons.

That in and of itself is fine, because the import logic is general
enough to handle both cases, but we have an assertion that seems to be
unaware of this scenario, and trips on unavailable NS_ENUMs. (In those
cases, the typedef points to the enum rather than the underlying integer
type.) This patch fixes the assertion to be resilient against such cases
by looking through the enum a typedef refers to.

This PR also includes some NFC commits which consolidate usage of the findOptionSetEnum() helper function. This pattern (and the failing assertion) was previously duplicated across six distinct locations across ImportDecl.cpp and ImportType.cpp. The interface and behavior of this function is based on findOptionSetType(), which was previously defined in ImportDecl.cpp but also used in ImportType.cpp via an ad hoc function declaration.

Those NFC commits make way for 80db054, where the actual fix is contained to a fairly small change.

rdar://150399978
Resolves #79636

j-hui added 2 commits May 19, 2025 14:10
…nction

Also renames it to findOptionSetEnum() to make it a bit clearer at face
value that the returned ImportedType will contain a Swift enum.

Also refactors some nearby instances of

  if (auto e = dyn_cast<ElaboratedType>(t))
      t = e->desugar();

into a helper function, desugarIfElaborated().
…EnumInfo.cpp

It's at home there alongside other ObjC enum-specific logic, rather than
in the middle of ImportDecl.cpp (since it isn't directly or exclusively
related to importing decls).
@j-hui
Copy link
Contributor Author

j-hui commented May 19, 2025

Draft PR with only NFC commits for now, to run under CI

@j-hui
Copy link
Contributor Author

j-hui commented May 19, 2025

@swift-ci please test

@j-hui
Copy link
Contributor Author

j-hui commented May 20, 2025

macOS tests are still hanging but Linux + Windows have passed, so it seems I didn't accidentally break anything with the [NFC] commits. Pushing actual patch + opening the PR now

@j-hui j-hui force-pushed the fix-unavailable-enum branch from bea20a2 to 75e4f04 Compare May 20, 2025 05:18
@j-hui j-hui marked this pull request as ready for review May 20, 2025 05:18
@j-hui
Copy link
Contributor Author

j-hui commented May 20, 2025

@egorzhdan for what it's worth, I tried explicitly checking for {CF,NS}_OPTIONS in this patch bea20a2 but it causes one of our regression tests that uses a custom macro to fail, so I'm not including that in this patch set. For the future, I'm wondering whether we should be explicitly checking for the enum_flag or enum_open attributes, rather than relying on heuristics like availability or the spelling of the macro used to produce these decls.

For now, 75e4f04 keeps the behavior consistent with what it was before, and simply adjusts the assertion to accommodate NS_ENUMs.

@j-hui
Copy link
Contributor Author

j-hui commented May 20, 2025

@swift-ci please test

@j-hui
Copy link
Contributor Author

j-hui commented May 20, 2025

I seem to have just missed #81636. Restarting tests

@j-hui
Copy link
Contributor Author

j-hui commented May 20, 2025

@swift-ci please test

Copy link
Contributor

@egorzhdan egorzhdan left a comment

Choose a reason for hiding this comment

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

Just a couple of minor comments, but this LGTM in general.

@j-hui j-hui force-pushed the fix-unavailable-enum branch from 75e4f04 to a9b744e Compare May 21, 2025 01:38
@j-hui j-hui requested a review from hnrklssn as a code owner May 21, 2025 01:38
@j-hui
Copy link
Contributor Author

j-hui commented May 21, 2025

@swift-ci please test

@j-hui j-hui requested a review from egorzhdan May 21, 2025 01:39
@j-hui
Copy link
Contributor Author

j-hui commented May 21, 2025

@egorzhdan thanks for the suggestions, I took both of them. Do you have thoughts on checking for expansion of the NS_OPTIONS macro, i.e., what I do in bea20a2?

@j-hui
Copy link
Contributor Author

j-hui commented May 21, 2025

@swift-ci please test

j-hui added 2 commits May 21, 2025 10:16
The NS_OPTIONS macro sometimes uses a pattern where it loosely
associates a typedef with an anonymous enum via a shared underlying
integer type (emphasis on "loosely"). The typedef is marked as
unavailable in Swift so as to not cause name ambiguity when we associate
the anonymous enum with said typedef. We use unavailability as
a heuristic during the import process, but that conflates NS_OPTIONS
with NS_ENUMs that can be marked as unavailable for entirely unrelated
reasons.

That in and of itself is fine, because the import logic is general
enough to handle both cases, but we have an assertion that seems to be
unaware of this scenario, and trips on unavailable NS_ENUMs. (In those
cases, the typedef points to the enum rather than the underlying integer
type.) This patch fixes the assertion to be resilient against such cases
by looking through the enum a typedef refers to.

rdar://150399978
@j-hui j-hui force-pushed the fix-unavailable-enum branch from a9b744e to fa5c4f2 Compare May 21, 2025 17:18
@j-hui
Copy link
Contributor Author

j-hui commented May 21, 2025

@swift-ci please test

Copy link
Contributor

@egorzhdan egorzhdan left a comment

Choose a reason for hiding this comment

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

Both this change and bea20a2 LGTM, thanks!

importer::findOptionSetEnum() uses some fragile heuristics to determine
whether a typedef is involved in the construction of a CF_OPTIONS or
NS_OPTIONS type. This patch adds an explicit check that the typedef is
expanded from either of those macros, to prevent, e.g., an unavailable
NS_ENUM, from being mistakenly recognized as an NS_OPTIONS.

Note that doing this is still kind of fragile, and prevents users from
building {NS,CF}_OPTIONS with their own macros. The right thing to do is
probably specifically look for the flag_enum attribute, but that is not
currently what we're doing for reasons whose discovery is left as
an exercise to the future git archaeologist.

This patch also removes (part of) a test case that builds
a CF_OPTIONS-like type with the "SOME_OPTIONS" macro, which is no longer
supported as of this patch.

rdar://150399978
@j-hui
Copy link
Contributor Author

j-hui commented May 21, 2025

@swift-ci please test

@j-hui
Copy link
Contributor Author

j-hui commented May 22, 2025

@swift-ci please test windows platform

@j-hui j-hui merged commit 828876f into swiftlang:main May 22, 2025
5 checks passed
hamishknight added a commit to hamishknight/swift that referenced this pull request May 22, 2025
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.

Assertion failure in importParameterType when importing getKnownFolderLocations on Xcode 16.2
2 participants