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
ClangImporter has logic that infers default arguments of certain C/C++ types, such as the types declared via `CF_OPTIONS`/`NS_OPTIONS` macros.
There were some workarounds in place which triggered for C++ interop mode specifically. The workarounds were applying a heuristic based on the name of the type, which tried to match the behavior to non-C++ interop mode for certain types from the OS SDK. That was not working well for user-defined types, causing source compatibility breakages when enabling C++ interop.
This change replaces the name-based heuristic with a more robust criteria.
See also 3791ccb6.
rdar://142961112
Clang recently started wrapping more types in `clang::ElaboratedType` after this change: https://reviews.llvm.org/D112374
This broke some assumptions in ClangImporter, specifically in enum handling logic. This change adjusts those.
Fixes these tests in rebranch:
* `Interop/Cxx/enum/anonymous-with-swift-name-module-interface.swift`
* `Interop/Cxx/enum/anonymous-with-swift-name-objc-module-interface.swift`
* `Interop/Cxx/enum/anonymous-with-swift-name.swift`
* `Interop/Cxx/enum/c-enums-NS_OPTIONS-NS_REFINED_FOR_SWIFT.swift`
* `Interop/Cxx/enum/c-enums-NS_OPTIONS.swift`
* `Interop/Cxx/enum/c-enums-withOptions-omit.swift`
* `Interop/Cxx/class/inheritance/fields-module-interface.swift`
* `Interop/Cxx/class/inheritance/fields.swift`
* `Interop/Cxx/class/inheritance/functions-module-interface.swift`
* `Interop/Cxx/class/inheritance/sub-types-module-interface.swift`
* `Interop/Cxx/class/inheritance/type-aliases-module-interface.swift`
This silences the instances of the warning from Visual Studio about not all
codepaths returning a value. This makes the output more readable and less
likely to lose useful warnings. NFC.
Still to do: test and fix up the use of multiple enum_extensibility
annotations, possibly with API notes. This is important because the
definition of NS/CF_ENUM /includes/ enum_extensibility(open) as of
Xcode 9.0; there should be a convenient out people can use to declare
exhaustive enums in C that's backwards-compatible.
They're all kept alive by Clang's ASTContext already. Since the enum
info is only accessible through the Clang importer, that's a
sufficient lifetime. (Note that this only works because all of the
strings are derived from text actually present in the C sources:
either attribute arguments or names of declarations.)
Fixes a small TODO and probably saves a tiny bit of memory usage.
Now that we have a EnumInfoCache per NameImporter which is per Clang
instance, we can just cache our EnumInfo based off of Clang decl,
rather than using a faux-USR technique. This greatly speeds up and
simplifies enum imports.
EnumInfos are requested about 200k times when building the module
cache for Foundation, and thousands of times for simple tests during
normal import, so efficiency here is important. While building module
caches, the EnumInfoCache is hit 99% of the time, and it is hit 98% of
the time during normal import with pre-built module caches.
NFC.
Now that we have per-Clang-instance NameImporters, we can drop the
2-phase initialization that was internally present in
NameImporter. This lets NameImporter host the EnumInfoCache directly,
and streamlines the APIs.
NFC
Delay initialization of the EnumInfoCache until a Clang instance is
ready, simplifying its interface and allowing us to finally make this
per-Clang-instance. This will allow us to further de-couple ImportName
from the importer imply, as well as allow us to use a more efficient
and simpler caching mechanism. It is now owned by the NameImporter.
NFC.
Pull off the caching code from the Impl and onto a new EnumInfoCache
class, that will be useful as we decouple import naming from the Impl
class state.
The Clang attribute allows one to state that a particular enumeration
type describes an error, and associates it with a particular domain
constant. However, due to lack of API notes support, this attribute
wasn't actually getting used. Instead, we had a number of explicit
extensions to enum types to make them conform to the _BridgedNSError
protocol explicitly.
Now that we have API notes, use them to make these enums into error
enums with the appropriate domain, so that the Clang importer will
synthesize the _BridgedNSError conformances. Then, remove all of the
explicit conformances---and with them, the overlays for 12 frameworks.
There is a small fix to more eagerly consider these conformances as
"used" if an expression is formed with the error enum as a value
type. This better ensures that the conformances will be available at
runtime when needed.
This cleanup is needed to implement SE-0112 (NSError bridging),
although it is useful by itself.
Rather than do whole-word common-word stripping, we only strip common
prefixes. This is not as powerful as what was originally intended, but
much less magical in the mapping into Swift.
Test case adjusted, and common utility functions exposed.
This is more of rdar://problem/24869070; StringRefs are leaking out of
importFullName still, in a DenseMap that can get deallocated. When we
cache this data, put them in "permanent" (Swift ASTContext) storage.
Also, make the cache kick in between when a module is built and when
it is used. This isn't actually an important case, but it makes it a
whole lot more common to actually see the use-after-free break things.
Fixes rdar://problem/24869070.
ns_error_domain can now be used to communicate with the ClangImporter
when an enum has an associated error domain string. In this case, when
we import it as a Swift enum, we can also synthesize a conformance to
_BridgedNSError.
This allows the creation of something like NS_ERROR_ENUM, in which the
developer can declare an enum for the purposes of error handling. Adds
Sema and executable tests demonstrating this funcionality.
In order for the imported ns_error_domain bridging to work, we have to
at some point forcibly pull in a _BridgedNSError conformance, as one
will not be pulled in normally. This is a problem, and is explicitly
signaled in the provided test case
Introduces new class, EnumInfo, just for the implementation of the
ClangImporter to encapsulate various computed information about the
enum we're importing.
This helps refactor some functionality, aids clarity, and also
prevents us from repeating calculations multiple times, as we were
doing with classifyEnum's macro-expansion tracking. Provides a base
where we can add more heavy lifting in classifyEnum in the future.