It does not take ownership of its non-trivial arguments, is a trivial
function type and therefore must not be destroyed. The compiler must
make sure to extend the lifetime of non-trivial arguments beyond the
last use of the closure.
%objc = copy_value %0 : $AnObject
%closure = partial_apply [stack] [callee_guaranteed] %16(%obj) : $@convention(thin) (@guaranteed AnObject) -> ()
%closure2 = mark_dependence %closure : $@noescape @callee_guaranteed () -> () on %obj : $AnObject
%user = function_ref @useClosure : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
apply %user(%closure2) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
dealloc_stack %closure : $() ->()
destroy_value %obj : $AnObject // noescape closure does not take ownership
SR-904
rdar://35590578
Specifically we add a groups of APIs for destructure operations. The destructure
helpers are a family of functions built around
emitDestructureValueOperation. These in ossa produce destructures and pass the
results off to the caller in some manner that hides the internal destructure
instruction. In non-ossa, the appropriate projections are created and passed off
to the caller.
In a previous commit, I banned in the verifier any SILValue from producing
ValueOwnershipKind::Any in preparation for this.
This change arises out of discussions in between John, Andy, and I around
ValueOwnershipKind::Trivial. The specific realization was that this ownership
kind was an unnecessary conflation of the a type system idea (triviality) with
an ownership idea (@any, an ownership kind that is compatible with any other
ownership kind at value merge points and can only create). This caused the
ownership model to have to contort to handle the non-payloaded or trivial cases
of non-trivial enums. This is unnecessary if we just eliminate the any case and
in the verifier separately verify that trivial => @any (notice that we do not
verify that @any => trivial).
NOTE: This is technically an NFC intended change since I am just replacing
Trivial with Any. That is why if you look at the tests you will see that I
actually did not need to update anything except removing some @trivial ownership
since @any ownership is represented without writing @any in the parsed sil.
rdar://46294760
We've been running doxygen with the autobrief option for a couple of
years now. This makes the \brief markers into our comments
redundant. Since they are a visual distraction and we don't want to
encourage more \brief markers in new code either, this patch removes
them all.
Patch produced by
for i in $(git grep -l '\\brief'); do perl -pi -e 's/\\brief //g' $i & done
Previously we would always calculate these instructions ownership dynamically
when asked and rely on the ownership verifier to catch if we made any
mistakes. Instead with this commit we move to a more static model where the
ownership that these instructions can take are frozen on construction. This is a
more static model that simplifies the ownership model.
I also eliminated a few asserts that are enforced in other places that caused
problems when parsing since we may not have a Function while Parsing (it was
generally asserts if a type was trivial).
In this commit I added a more convenient API for doing this sort of operation.
Specifically: SILBuilder::emitScopedBorrowOperation. This performs either a
load_borrow or begin_borrow, then calls a user provided closure, and finally
inserts the end_borrow after the scope has closed.
rdar://43398898
Allow a new SILBuilder to be created for an insertion point, while
providing all of its necessary context.
Ultimately, the builder's constructor should take an insertion point,
DebugLocation, and context. Then we won't need to pass SILLocation to
all of its methods.
This makes much more sense and is much safer than saving the insertion
point via an RAII object or defining a separate
SILBuilderWithScope. Those broken abstractions should go away.
I changed all of the places that used end_borrow_argument to use end_borrow.
NOTE: I discovered in the process of this patch that we are not verifying
guaranteed block arguments completely. I disabled the tests here that show this
bad behavior and am going to re-enable them with more tests in a separate PR.
This has not been a problem since SILGen does not emit any such arguments as
guaranteed today. But once I do the SILGenPattern work this will change.
rdar://33440767
This does not eliminate the entrypoints on SILBuilder yet. I want to do this in
two parts so that it is functionally easier to disentangle changing the APIs
above SILBuilder and changing the underlying instruction itself.
rdar://33440767
Each of its overloads immediately calls a method on it, so it’s not valid to pass a null pointer. Instead, call clearInsertionPoint() when the SavedIP is null in SavedInsertionPointRAII.
ConvertFunction and reabstraction thunks need this attribute. Otherwise,
there is no way to identify that withoutActuallyEscaping was used
to explicitly perform a conversion.
The destination of a [without_actually_escaping] conversion always has
an escaping function type. The source may have either an escaping or
@noescape function type. The conversion itself may be a nop, and there
is nothing distinctive about it. The thing that is special about these
conversions is that the source function type may have unboxed
captures. i.e. they have @inout_aliasable parameters. Exclusivity
requires that the compiler enforce a SIL data flow invariant that
nonescaping closures with unboxed captures can never be stored or
passed as an @escaping function argument. Adding this attribute allows
the compiler to enforce the invariant in general with an escape hatch
for withoutActuallyEscaping.
Fixes <rdar://40555427> [SR-7773]:
SILCombiner::propagateConcreteTypeOfInitExistential fails to full propagate type
substitutions.
Fixes <rdar://problem/40923849>
SILCombiner::propagateConcreteTypeOfInitExistential crashes on protocol
compositions.
This rewrite fixes several fundamental bugs in the SILCombiner optimization that
propagates concrete types. In particular, the pass needs to handle:
- Arguments of callee Self type in non-self position.
- Indirect and direct return values of Self type.
- Types that indirectly depend on Self within callee function signature.
- Protocol composition existentials.
- All of the above need to work for protocol extensions as well as witness methods.
- For protocol extensions, conformance lookup should be based on the existential's conformance list.
Additionally, the optimization should not depend on a SILFunction's DeclContext,
which is not serialized. (In fact, we should prevent SIL passes from using
DeclContext). Furthermore, the code needs to be expressed in a way that one can
reason about correctness and invariants.
The root cause of these bugs is that SIL passes are written based on untested
assumptions of Swift type system. A SIL pass needs to handle all verifiable SIL
input because passes need to be composable. Bail-out logic can be added to
simplify the design; however, _the bail-out logic itself cannot make any
assumptions about the language or type system_ that aren't clearly and
explicitly enforced in the SIL verifier. This is a common mistake and major
source of bugs.
I created as many unit tests as I reasonably could to prevent this code from
regressing. Creating enough unit tests to cover all corner cases that were
broken in the original code would be intractable. But the code has been
simplified such that many corner cases disappear.
This opens up some oportunity for generalizing the optimization and eliminating
special cases. However, I want this PR to be limited to fixing correctness
issues only. In the long term, it would be preferable to replace this
optimization entirely with a much more powerful general type propagation pass.
In an upcoming bug fix, I want to pass SILBuilderContext to a
utility. I could continue reusing SILBuilder, even though the utility
must set its own insertion point and debug location. However, this is
terrible practice that I don't want to perpetuate.
The lifetime of a SILBuilder should correspond to a single insertion
point and debug location. That's the only sane way to preserve debug
information in SIL passes.
There are various pieces of contextual state that we've been adding to
the SILBuilder. Those have made it impossible to use SILBuilder
correctly. I'm pulling the context out, so clients can begin using
better practices. In the future, we can make SILBuilderContext
polymorphic, so passes can extend it easily with arbitrary
callbacks. We can also make it self-contained so we don't need to pass
around pointers to an InsertedInst list anymore.
This flag supports promoting KeyPath access violations to an error in
Swift 4+, while building the standard library in Swift 3 mode. This is
only necessary as long as the standard library continues to build in
Swift 3 mode. Once the standard library build migrates, it can all be
ripped out.
<rdar://problem/40115738> [Exclusivity] Enforce Keypath access as an error, not a warning in 4.2.
Mandatory pass will clean it up and replace it by a copy_block and
is_escaping/cond_fail/release combination on the %closure in follow-up
patches.
The instruction marks the dependence of a block on a closure that is
used as an 'withoutActuallyEscaping' sentinel.
rdar://39682865
To mark when a user of it is known to escape the value. This happens
with materializeForSet arguments which are captured and used in the
write-back. This means we need to keep the context alive until after
the write-back.
Follow-up patches to fully replace the PostponedCleanup hack in SILGen
by a mandatory SIL transformation pass to guarantee the proper lifetime
will use this flag to be more conservative when extending the lifetime.
The problem:
%pa = partial_apply %f(%some_context)
%cvt = convert_escape_to_noescape [not_guaranteed] [escaped] %pa
%ptr = %materialize_for_set(..., %cvt)
... write_back
... // <-- %pa needs to be alive until after write_back