A recent refactoring uncovered two places where we could end up
importing a C++ field declaration as a property more than once:
1. Importing the declaration context of a field in C++ mode can then
go import all of the fields. In such a case, check that the field
we're importing didn't happen already, and bail out early if it did.
This is common practice in the Clang importer but wasn't happening here.
2. One caller to the function that imported a field from a C++ base
class into its inheriting class (as a computed property) wasn't
checking the cache, and therefore created a redundant version.
Fix both issues.
When importing a C header in the C++ language mode, Clang/Swift treat C structs as C++ structs.
Currently Swift synthesizes a default initializer that zero-initializes the backing memory of the struct for C structs, but not for C++ structs.
This is causing issues in existing projects that use C libraries and rely on having the default initializer available in Swift. This change enables the synthesis of a default initializer for C++ structs. Since many C++ structs are not designed to be initialized this way, the initializer is marked as deprecated in Swift.
rdar://109727620
The lookup to resolve an ObjC forward declaration
to its potential native Swift definition within
a mixed module is becoming cyclic somehow.
The old uncached lookup still works, so it seems
this is an issue with cache invalidation somehow.
Until the route of the issue, use the old uncached
lookup method.
When swift-frontend is explicitly passed the pch file as bridging header
on command-line through `-import-objc-header`, it needs to print the
original source file name if needed to the generated objc header.
rdar://109411245
When using explicit module build, there is no need to check top level
module map to see if the module exists or not, since dependency scanning
already pulled in all needed modules. Furthermore, when using clang
include tree, the module maps are not available through FS for this
search. Just directly try to load modules when using explicit module
build.
When creating ClangImporter directly from cc1 args, there is no need for
clang path, and it might even be mistaken as an input path. Don't use
clang executable path in the arguments when creating from cc1 commands.
The Clang importer's Clang instance may be configured with a different (higher)
OS version than the compilation target itself in order to be able to load
pre-compiled Clang modules that are aligned with the broader SDK, and match the
SDK deployment target against which Swift modules are also built. In this case,
we must use the Swift compiler's OS version triple in order to generate the
binary as-requested.
This change makes 'ClangImporter' 'Implementation' keep track of a distinct
'TargetInfo' and 'CodeGenOpts' containers that are meant to be used by clients
in IRGen. When '-clang-target' is not set, they are defined to be copies of the
'ClangImporter's built-in module-loading Clang instance. When '-clang-target' is
set, they are configured with the Swift compilation's target triple and OS
version (but otherwise identical) instead. To distinguish IRGen clients from
module loading clients, 'getModuleAvailabilityTarget' is added for module
loading clients of 'ClangImporter'.
The notion of using a different triple for loading Clang modules arises for the
following reason:
- Swift is able to load Swift modules built against a different target triple
than the source module that is being compiled. Swift relies on availability
annotations on the API within the loaded modules to ensure that compilation
for the current target only uses appropriately-available API from its
dependencies.
- Clang, in contrast, requires that compilation only ever load modules (.pcm)
that are precisely aligned to the current source compilation. Because the
target triple (OS version in particular) between Swift source compilation and
Swift dependency module compilation may differ, this would otherwise result in
builtin multiple copies of the same Clang module, against different OS
versions, once for each different triple in the build graph.
Instead, with Explicitly-Built Modules, Swift sets a '-clang-target' argument
that ensures that all Clang modules participating in the build are built against
the SDK deployment target, matching the Swift modules in the SDK, which allows
them to expose a maximally-available API surface as required by
potentially-depending Swift modules' target OS version.
--------------------------------------------
For example:
Suppose we are building a source module 'Foo', targeting 'macosx10.0', using an
SDK with a deployment target of 'macosx12.0'. Swift modules in said SDK will be
built for 'macosx12.0' (as hard-coded in their textual interfaces), meaning they
may reference symbols expected to be present in dependency Clang modules at that
target OS version.
Suppose the source module 'Foo' depends on Swift module 'Bar', which then
depends on Clang module `Baz`. 'Bar' must be built targeting 'macosx12.0'
(SDK-matching deployment target is hard-coded into its textual interface). Which
means that 'Bar' expects 'Baz' to expose symbols that may only be available when
targeting at least 'macosx12.0'. e.g. 'Baz' may have symbols guarded with
'__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_12_0'. For this reason, we use
'-clang-target' to ensure 'Baz' is built targeting 'macosx12.0', and can be
loaded by both 'Foo' and 'Bar'.
As a result, we cannot direclty use the Clang instance's target triple here and
must check if we need to instead use the triple of the Swift compiler instance.
Resolves rdar://109228963
This will mean that '-disable-implicit-swift-modules' also automatically implies two things:
1. Clang modules must also be explicit, and the importer's clang instance will get '-fno-implicit-modules' and '-fno-implicit-module-maps'
2. The importer's clang instance will no longer get a '-fmodules-cache-path=', since it is not needed in explicit builds
This better matches what the clang importer does
normally, avoids a Clang issue where
`getPreprocessedEntitiesInRange` returns incorrect
results, and avoids the need to enable the
preprocessor record. This then lets us re-enable
`print_clang_headers.swift`.
rdar://102151774
If two different C++ structs have methods with the same name, both annotated with `SWIFT_COMPUTED_PROPERTY`, ClangImporter previously confused them when one of the structs referenced the other struct.
rdar://108990490 / resolves https://github.com/apple/swift/issues/65675
Clang implicitly enables local submodule visibility when compiling in C++20 mode. ClangImporter does not support it, so let's disable it explicitly.
rdar://108959307 / https://github.com/apple/swift/issues/65710
The Swift compiler does not have a concept of a working directory. It is instead handled by the Swift driver by resolving relative paths according to the driver's working directory argument. On the other hand, Clang does have a concept working directory which may be specified on this Clang invocation with '-working-directory'. If so, it is crucial that we use this directory as an argument to the Clang scanner API. Otherwiswe, we risk having a mismatch between the working directory specified on the scanner's Clang invocation and the one use from the scanner API entry-points, which leads to downstream inconsistencies and errors.
This was originally fixed for the main by-name module dependencies query in https://github.com/apple/swift/pull/61025 (03136e06aa), but the Bridging Header dependencies code has continued to incorrectly expect the Swift ASTContext to both have the working directory set *and* be consistent with that of the Clang scanner instance.
Resolves rdar://108464467