This moves processing of the Swift return type in `swiftify` as late as
possible, so that we only trigger importing of the return type if we
really need it (because we are about to attach the macro and need to
verify that it's safe to do so). This fixes an exponential type import
in Interop/Cxx/templates/large-class-templates-module-interface.swift
that was introduced when the early check for template instantiations in
the signature was removed, causing `swiftify` to reach the return type
import stage for a function with a really expensive template type in its
return type. Note that the test would still pass with the experimental
ImportCxxMembersLazily feature enabled. But regardless, we should strive
to be as lazy as possible in our importing even in `swiftify`.
We previously prevented generating safe wrappers on functions with
template instantiations in the signature, unless those instantiations
were hidden behind a typedef. This is because those template
instantiations cannot be expressed in Swift syntax, so the macro
would expand to a function with invalid syntax.
For the std::span parameter itself however, that type is replaced with a
Swift Span in the safe wrapper, so it's not an issue in the type
signature. We would previously use the std::span type name from the
original signature to cast from Span to std::span, which does not work
with the raw std::span type. This uses `.init` instead when this is the
case, which avoids spelling out the type. When possible, we still use
the concrete type name, for clarity and by providing information we have
accessible the typechecker needs to do less work.
Resolves#86339
rdar://167712240
We wrote the same code multiple times, this PR replaces some of that
code with function calls. It is not entirely NFC as the called function
has some special case for parameters. That being said, having uniform
logic for looking up attributes is probably beneficial. If it does not
work out, we can always introduce a compile-time parameter to opt in/out
of the special case.
When safe interop was stabilized, lifetimebound deliberately not
stabilized. The check for lifetimebound on the implicit "this" parameter
was accidentally not gated behind the experimental feature check,
however. Now lifetimebound on implicit "this" is no longer in the stable
feature set.
rdar://175396896
Since 60d5ce8f19 stdlib availability is
substituted with an empty availability when targeting Embedded Swift,
since availability is irrelevant when statically linked. This resulted
in the _SwiftifyImport macro expansion containing an `@available(, *)`
annotation, which is syntactically invalid. Avoid this by simply not
including an availability parameter.
rdar://174341000
* Simplify some patterns (isa + cast)
* Add some consts
* Get rid of some temporary objects by constructing more objects in
place
* Remove some duplicated lookups
* Other minor cleanups
This class is unused since safe interop wrapper support for ObjC methods
was backed out. When we reintroduce this, it will be implemented
differently, and this class won't be necessary - at least in its current
reincarnation. Move as much as possible into swiftifyImpl, making
swiftify a thin wrapper around it. This thin wrapper will be relevant
when we reimplement support for ObjC methods.
This adds SWIFT_NO_SAFE_WRAPPER, which can be used to signal that a
function should not get a safe interop wrapper. This can serve as a
fallback if a safe wrapper blocks compilation, while waiting for a fix
to ship.
rdar://169146789
This adds another case where parameter counts can mismatch, found in
test/IDE/Inputs/custom-modules/ImportAsMember.h:
```
extern struct IAMStruct1 IAMStruct1CreateSpecialLabel(void)
__attribute__((swift_name("Struct1.init(specialLabel:)")));
```
This takes a function with no parameters and imports it as a constructor
with a single parameter taking the Void type.
swift-synthesize-interface needs to match the safe interop wrappers
setting of the compiler invocation that built the Swift module, but
doesn't have -enable/disable-experimental-feature options. Instead of
introducing them for a single feature, which isn't even experimental,
this introduces the -disable-safe-interop-wrappers instead.
lifetimebound does not imply that the parameter does not escape. For
stabilising safe wrappers we don’t want to use that assumption, so we
need a new feature flag.
rdar://170090534
This adds support for safe wrappers on imported functions returning a
~Escapable value. This is only done if there is lifetime information for
the return value, as the wrapper will always have a lifetime error
otherwise. __lifetimebound is also ignored *unless* the return value is
~Escapable (or will be transformed to a Span), since lifetime info for
an Escapable return value is an error. To enable testing this it also
adds merging of lifetime annotations from the underlying funciton and
the extra info added by the macro.
rdar://157884394
Checking the escapability of types at this point during compilation can
return the wrong result and prevent the correct result from being
calculated later due to caching.
rdar://169839008
This linearizes the macro expansions by leaking the internal buffer
pointer in [Mutable][Raw]Span parameters. This avoids the closure-based
nesting, simplifying the function body, but more importantly avoids an
error when the function is an intializer: Swift does not allow calls to
delegated initializers inside other expressions or closures.
Initializers for CoreFoundation-style references are not allowed at all
(other than the ones imported from C), so safe wrappers on those are
avoided entirely.
rdar://169661706
At the moment plugin paths do not get passed along when consuming a
textual interface of an imported module. Normally this is not an issue,
because all macros have already been expanded at this point, but this is
not the case for _SwiftifyImport which belongs to a clang module but is
expanded while gompiling a dependent Swift module. This would cause an
error when trying to expand the macro. Since most textual interfaces
don't call any safe wrappers at the moment, this unblocks the
compilation by checking whether the macro plugin can be loaded before
attaching the macro, and emitting a warning if not. Long term we'll want
to pass along the plugin path to swift-api-digester, but this will do
for now.
rdar://168967555
This removes the swiftifyProtocol function, because it fundamentally
incompatible with our layering. By iterating over the protocol members
of the node we are currently importing, we immediately force all members
to be imported. This can lead to cycles and various hard-to-debug import
failures. Instead we need to attach the extension macro when importing
each invidvidual method. This will take some plumbing however, because
that may happen after the protocol's macros have already been expanded,
preventing later macros from being expanded.
rdar://168500103
This aligns the logic in SwiftifyDecl.cpp for fetching the owning module
with that of the rest of the compiler. Previously we would fetch the
owning module from the clang decl directly associated with the Swift
decl, whereas the rest of the compiler looks at the canoncial (first)
decl to determine ownership. This mismatch resulted in a state where
swiftifyImpl did not think the decl originated in a bridging header
(because it was not imported into the __ObjC module), but it also didn't
find an owning module on the clang decl. This occured when a bridging
header would import a header from a module, and then redeclare a
function from that module.
rdar://168703691
This fixes two bugs:
1) The outermost pointee type is not necessarily a nominal type. There
can e.g. be a pointer to an array (tuple) type. This would result in a
null pointer dereference. Instead of assuming direct pointee nominal
types, we now check for nominal types anywhere in the type hierarchy.
2) Enum types can also be forward declared. Instead of checking for
clang::RecordDecl, we now check for clang::TagDecl (which is a base
class of clang::RecordDecl and clang::EnumDecl).
rdar://165864358
This prevents stuff like memcmp from SwiftShims from being imported with
@_SwiftifyImport, which would then result in name lookup errors as it
does not import the Swift standard library module. This makes the
previous approach to disable safe interop when compiling with
-parse-stdlib redundant.
irdar://165856959
Since decls with no module are imported to __ObjC this is not an issue,
because __ObjC is always implicitly imported. Added test case that would
previously assert.
This fixes an assert when signatures contain
`struct forward_declared_t **`, and makes sure that
`struct foo { struct forward_declared_t *bar; }` does *not* block
swiftification, since `@_SwiftifyImport` does not need to access the
struct field.
Implicit decls don't have an owning module, since multiple modules could
instantiate them on demand. Since no implicit functions currently have
any need for safe wrappers we can simply detect this and early exit. For
templated functions, we need to fetch the owning module from the
instantiation.
A Swift module only imports a type definition once. This means that some
clang modules may have function signatures imported with
`UnsafePointer<qux>` even if `qux` is only forward declared in that
module (which would normally be imported as `OpaquePointer`), because
some Swift file in the module imported the clang module with the
definition, so ClangImporter sees the definition. The macro expansion
only imports the imports of the clang module it belongs to however, so
namelookup for `qux` fails. This patch detects when this will result in
an error and avoids attaching the macro in those cases.
rdar://165864358
These cases would trigger an assert in both release and debug builds.
With this change they are ignored in release mode, and cases that are
both unhandled and unknown trigger an assert in debug mode.
rdar://166074719
This adds automatic scope management and indentation to the logs to make
them more structured. Also adds some additional logging.
Here's an example of what it can look like now:
```
[swiftify:593] Checking 'CountedByProtocol' protocol for methods with bounds and lifetime info
[swiftify:350] | Checking 'simple::' for bounds and lifetime info
[swiftify:411] | | Checking parameter 'len' with type 'int'
[swiftify:411] | | Checking parameter 'p' with type 'int * __counted_by(len)'
[swiftify:435] | | | Found bounds info 'int * __counted_by(len)'
[swiftify:350] | Checking 'shared:::' for bounds and lifetime info
[swiftify:411] | | Checking parameter 'len' with type 'int'
[swiftify:411] | | Checking parameter 'p1' with type 'int * __counted_by(len)'
[swiftify:435] | | | Found bounds info 'int * __counted_by(len)'
[swiftify:411] | | Checking parameter 'p2' with type 'int * __counted_by(len)'
[swiftify:435] | | | Found bounds info 'int * __counted_by(len)'
[swiftify:350] | Checking 'complexExpr:::' for bounds and lifetime info
[swiftify:411] | | Checking parameter 'len' with type 'int'
[swiftify:411] | | Checking parameter 'offset' with type 'int'
[swiftify:411] | | Checking parameter 'p' with type 'int * __counted_by(len - offset)'
[swiftify:435] | | | Found bounds info 'int * __counted_by(len - offset)'
[swiftify:350] | Checking 'nullUnspecified::' for bounds and lifetime info
[swiftify:411] | | Checking parameter 'len' with type 'int'
[swiftify:411] | | Checking parameter 'p' with type 'int * __counted_by(len) _Null_unspecified'
[swiftify:435] | | | Found bounds info 'int * __counted_by(len) _Null_unspecified'
[swiftify:350] | Checking 'nonnull::' for bounds and lifetime info
[swiftify:411] | | Checking parameter 'len' with type 'int'
[swiftify:411] | | Checking parameter 'p' with type 'int * __counted_by(len) _Nonnull'
[swiftify:435] | | | Found bounds info 'int * __counted_by(len) _Nonnull'
[swiftify:350] | Checking 'nullable::' for bounds and lifetime info
[swiftify:411] | | Checking parameter 'len' with type 'int'
[swiftify:411] | | Checking parameter 'p' with type 'int * __counted_by(len) _Nullable'
[swiftify:435] | | | Found bounds info 'int * __counted_by(len) _Nullable'
[swiftify:350] | Checking 'returnPointer:' for bounds and lifetime info
[swiftify:379] | | Found bounds info 'int * __counted_by(len)' on return value
[swiftify:411] | | Checking parameter 'len' with type 'int'
[swiftify:350] | Checking 'staticMethod::' for bounds and lifetime info
[swiftify:411] | | Checking parameter 'len' with type 'int'
[swiftify:411] | | Checking parameter 'p' with type 'int * __counted_by(len)'
[swiftify:435] | | | Found bounds info 'int * __counted_by(len)'
```
This updates SwiftifyImportProtocolPrinter such that it no longer emits
anything for methods without bounds or lifetime info. Previously we
would not attach the macro if no methods in the protocol contained
bounds or lifetime info. However if one of the methods did, we would
still emit `.method(signature: "func foo()", paramInfo: [])` for the
methods without bounds of lifetime info. This would result in overloads
being generated, like so:
```
@_alwaysEmitIntoClient @_disfavoredOverload public
func foo() {
return unsafe foo()
}
```
As part of this change, SwiftifyImportPrinter is now an abstract parent
type for SwiftifyImportProtocolPrinter, and the new
SwiftifyImportFunctionPrinter. Instead of SwiftifyImportProtocolPrinter
inheriting the function printing, `printMethod` instead creates a new
SwiftifyImportFunctionPrinter each time, with a new output string. If it
output anything interesting the result is forwarded, otherwise it is
discarded.
...with bounds attributes
This creates safe overloads for any methods in the protocol annotated
with bounds information. Updates _SwiftifyImportProtocol to make the
added overloads in the protocol public.
rdar://144335990
This code doesn't interact that much with the rest of ClangImporter, and
will continue to grow. Keeping it in a separate file makes it easier to
navigate.