Previously we would emit a macro that would error on expansion when
trying to add a safe wrapper to a function with __sized_by on a type
that mapped to UnsafePointer<T> instead of UnsafeRawPointer or
OpaquePointer. __sized_by is acceptable when used on byte-sized pointee
types, so this adds machinery in the macro expansion to support that.
Meanwhile on the ClangImporter side, we add a check so that __sized_by
on pointee types with a size is ignored if that size is larger than 1
byte.
When _SwiftifyImport applies .sizedBy to a pointer of type
UnsafePointer<T> it will still map it to a
RawSpan/UnsafeRawBufferPointer in the safe overload. The assumption is
that any API using __sized_by is dealing with raw bytes, so raw pointers
are a better Swift abstraction than UnsafePointer<CChar> etc. It also
lets the user avoid doing a scary pointer cast from some potentially
larger-than-byte-sized pointer to a byte-sized pointer. Casts to
RawPointers are generally safer and more ergonomic.
rdar://150966684
rdar://150966021
Previously we did not remove count parameters if any count parameters
were shared between count expressions, or if any count expression
contained operations. Buffer sizes were also just checked to be larger
than or equal than the given count.
We now extract the count from Spans/BufferPointers whenever possible,
and store that value in a variable at the start of the function. If
multiple parameters share the same count, a bounds check is emitted to
make sure that they have the same size. Subspans can be used if one span
is larger than necessary.
The message in the bounds check is changed so that it includes the
expected and actual value, to aid in debugging.
This patch also fixes some incorrect indentation, and adds the
Whitespace.swift test case to act as a regression test in case the
indentation changes, since the other test cases don't use significant
whitespace.
rdar://151488820
rdar://151511090
rdar://146333006
rdar://147715799
Previously we would only add @_disfavoredOverload if the only type
changed was the return type, because in any other case it is unambiguous
which overload to call. However it is still ambiguous when storing the
function as a value rather than calling the function, unless explicit
type annotations are used.
To avoid breaking any existing code, this patch adds
@_disfavoredOverload to every overload generated by @_SwiftifyImport.
rdar://151206394
Parameters can be named with keywords without escaping, because it's
unambiguous in the grammar that they are parameters. They still need to
escaped when referred to inside the function body however. This escapes
all references to parameters using backticks.
Parameter names are also checked for clashes with the function name - in
such cases the parameter is renamed in the same way as unnamed
parameters.
rdar://151024645
Nullable return Spans did not include __swiftifyOverrideLifetime,
resulting in a lifetime error when returning the Span. Meanwhile return
values for __sized_by did not use the correct label for the call to the
RawSpan initializer, using `count` instead of `byteCount`.
rdar://151804085
rdar://151799287
_SwiftifyImport would expand with syntax errors if applied to a function
with anonymous parameters, because it would try to refer to parameters
using the name `_`. Detect these cases and create names for unnamed
parameters.
rdar://150955944
* [Swiftify] Emit Mutable[Raw]Span when possible
Previously wrappers would use UnsafeMutable[Raw]Pointer for mutable
pointers, and Span for non-const std::span, to prevent the compiler from
complaining that MutableSpan didn't exist.
Now that MutableSpan has landed we can finally emit MutableSpan without
causing compilation errors. While we had (disabled) support for MutableSpan
syntax already, some unexpected semantic errors required additional
changes:
- Mutable[Raw]Span parameters need to be inout (for mutation)
- inout ~Escapable paramters need explicit lifetime annotations
- MutableSpan cannot be directly bitcast to std::span, because it is
~Copyable, so they need unwrapping to UnsafeMutableBufferPointer
rdar://147883022
* [Swiftify] Wrap if-expressions in Immediately Called Closures
When parameters in swiftified wrapper functions are nullable, we use
separate branches for the nil and nonnil cases, because
`withUnsafeBufferPointer` (and similar) cannot be called on nil.
If-expressions have some limitations on where they are allowed in the
grammar, and cannot be passed as arguments to a function. As such, when
the return value is also swiftified, we get an error when trying to
pass the if-expression to the UnsafeBufferPointer/Span constructor.
While it isn't pretty, the best way forward seems to be by wrapping the
if-expressions in Immediately Called Closures.
The closures have the side-effect of acting as a barrier for 'unsafe':
unsafe keywords outside the closure do not "reach" unsafe expressions
inside the closure. We therefore have to emit "unsafe" where unsafe
expressions are used, rather than just when returning.
rdar://148153063
__counted_by already had MutableSpan support, so add it for std::span
for parity. But since MutableSpan hasn't landed in the standard library
yet, disable emitting it to prevent compilation errors in expansions.
rdar://147882736
Casting the return value to Span must be done outside
withUnsafeBufferPointer, to prevent returning a ~Escapable type from a
function without lifetime info. To do this we sort the transformations
so that the return value transformation is performed last. There was
a bug in the comparison, so the sorting was not always done correctly.
rdar://147934170
When an imported function combines std::span and __counted_by,
std::span would override bounds checks emitted for __counted_by (if it
occurred later in the the parameter list) resulting in no bounds checks
being emitted.
rdar://147883384
Do not rely on the @_unsafeNonescapableResult attribute. That attribute is only
for temporarily working around bugs! And it only affects lifetime diagnostics within
the function. It has no affect on the caller's diagnostics, so it won't solve
this problem:
func macroGeneratedThunk() -> CxxSpan<Int> {
return _unsafeRemoveLifetime(Span...)
}
We cannot simply add @_unsafeRemoveLifetime to the thunk, because SwiftSyntax
does not natively support the attribute. We don't want to add SwiftSyntax
support because this attribute will never be supported syntax!
Instead, use `_overrideLifetime` copying the `Void` type to remove a dependency:
func macroGeneratedThunk() -> CxxSpan<Int> {
return _cxxOverrideLifetime(Span..., copying: ())
}
We use experimental features to let people know that the construct is
subject to change and users should not rely on this unless they are
willing to rewrite the uses of this feature later. However, in compiler
generated code everything should be fair game, we will update the
compiler when these features change. This is a requirement to be able to
turn safe wrapper generation on by default.
[Swiftify][StrictMemorySafety] Test `unsafe` warnings in wrappers (NFC)
As _SwiftifyImport now emits the `unsafe` keyword to prevent warnings
about unsafe code in the macro expansions, we should make sure that our
tests do not emit any warnings. It turns out that calls to
RawSpan::withUnsafeRawPointer are not recognised as unsafe, so we
sometimes get warnings about using `unsafe` on a safe expression. This
issue is tracked under rdar://145899513.
The generated safe wrappers need to call unsafe code. Make sure those
calls are qualified with unsafe to avoid warnings that are not
actionable (users cannot fix them).
__counted_by return values with .lifetimeDependence are now mapped to
Span instead of UnsafeBufferPointer. Also fixes bug where std::span
return values would map to Span even if lifetime dependence info was
missing.
Usage of Span was temporarily behind an experimental feature flag. Now
that SE-0447 has been accepted, remove the experimental feature flag and
allow Span usage everywhere.
Implements rdar://144819992.
Unfortunately, this was not discovered earlier as swift-ide-test is not
invoking the SIL passes that produce this diagnostic. When creating
Swift spans from C++ spans we have no lifetime dependency information to
propagate as C++ spans are modeled as escapable types. Hence, this PR
introduces a helper function to bypass the lifetime checks triggered by
this discepancy. Hopefully, the new utility will go away as the lifetime
analysis matures on the Swift side and we get standardized way to deal
with unsafe lifetimes.
When we generate a safe wrapper that only differs in the return type we
might introduce ambiguities as some callers might not have enough
information to disambiguate between the overloads. This PR makes sure
the newly generated declarations are marked as @_disfavoredOverload so
the compiler can keep calling the old functions without a source break
when the feature is turned on.
rdar://139074571
Support adding safe wrappers for APIs returning std::span depending on
the this object. This also fixes an issue for APIs with 0 parameters.
rdar://139074571
This PR adds basic support for storing lifetime dependence information,
transform Span return types, and generate lifetime annotations.
rdar://139074571
* Import __counted_by for function return values
Instead of simply passing a parameter index to _SwiftifyInfo, the
_SwiftifyExpr enum is introduced. It currently has two cases:
- .param(index: Int), corresponding to the previous parameter index
- .return, corresponding to the function's return value.
ClangImporter is also updated to pass this new information along to
_SwiftifyImport, allowing overloads with buffer pointer return types to
be generated. The swiftified return values currently return Span when
the return value is marked as nonescaping, despite this not being sound.
This is a bug that will be fixed in the next commit, as the issue is
greater than just for return values.
* Fix Span variant selection
There was an assumption that all converted pointers were either
converted to Span-family pointers, or UnsafeBufferPointer-family
pointers. This was not consistently handled, resulting in violating the
`assert(nonescaping)` assert when the two were mixed. This patch removes
the Variant struct, and instead each swiftified pointer separately
tracks whether it should map to Span or UnsafeBufferPointer.
This also fixes return pointers being incorrectly mapped to Span when
marked as nonescaping.
A previous PR already added support to the SwiftifyImport macro to
generate safe wrappers. This PR makes ClangImporter emit the macro to do
the transformation.
This makes it possible to mark a pointer with __sized_by when the
pointee type definition is not included. The wrapper function has the
same interface as if the parameter were a void pointer, since the stdlib
has no `OpaqueBufferPointer` type.
* use swift-ide-test for checking interop signatures
* add xfail test for Span + Optional combo (Optional requires Escapable)
This is a preliminary PR to transform nonescaping std::span parameters
to Swift's Span type in safe wrappers. To hook this up with
ClangImporter, we will need generalize the noescape attribute to
non-pointer types (PR is already in review). To transform potentially
escaping spans and spans in the return position, a follow-up PR will
add lifetime annotation support. This is a building block towards
rdar://139074571.
* Make pointer bounds non-experimental
* Rename @PointerBounds to @_SwiftifyImport
* Rename filenames containing PointerBounds
* Add _PointerParam exception to stdlib ABI test
* Add _PointerParam to stdlib API changes
* Rename _PointerParam to _SwiftifyInfo