Extend the checks in `LifetimeChecker` in
`SILOptimizer/Mandatory/DefiniteInitialization.cpp`
to catch when the memory object corresponding to a let constant is used
as an inout parameter in a protocol witness method.
Initializing a let constant separate from its declaration requires write
access. Therefore it is treated as `@lvalue TestProtocol` in the AST for
a certain scope.
Checking that the constant is not written to after being initialized is
supposed to happen in the Mandatory SILOptimizer phase instead.
On loads, the Optimizer checks, that a variable is fully initialized,
but perviously did not validate what happens to it after it is loaded.
This allowed loading the memory object through an open_existential_addr
instruction and applying the result as an Operand to a mutating witness
method.
Previously, we were only able to detect factory initializers
dispatched through class_method. This didn't work for
factory initializers defined in protocol extensions.
The end result would be that we would strong_release an
uninitialized class instance, which could cause crashes.
Fix DI to correctly release the old instance using
dealloc_partial_ref instead.
Fixes <rdar://problem/27713221>.
In failable initializers the "return from initializer without initializing all stored properties" (resp. "return from enum initializer method without storing to 'self'" for enums) diagnostic is now reported at the early return instead of the end of the initializer.
We were giving special handling to ApplyInst when we were attempting to use
getMemoryBehavior(). This commit changes the special handling to work on all
full apply sites instead of just AI. Additionally, we look through partial
applies and thin to thick functions.
I also added a dumper called BasicInstructionPropertyDumper that just dumps the
results of SILInstruction::get{Memory,Releasing}Behavior() for all instructions
in order to verify this behavior.
As there are no instructions left which produce multiple result values, this is a NFC regarding the generated SIL and generated code.
Although this commit is large, most changes are straightforward adoptions to the changes in the ValueBase and SILValue classes.
This change is needed for the next update to ToT LLVM. It can be put
into place now without breaking anything so I am committing it now.
The churn upstream on ilist_node is neccessary to remove undefined
behavior. Rather than updating the different ilist_node patches for the
hacky change required to not use iterators, just use iterators and keep
everything as ilist_nodes. Upstream they want to eventually do this, so
it makes sense for us to just do it now.
Please do not introduce new invocations of
ilist_node::get{Next,Prev}Node() into the tree.
And use project_box to get to the address value.
SILGen now generates a project_box for each alloc_box.
And IRGen re-uses the address value from the alloc_box if the operand of project_box is an alloc_box.
This lets the generated code be the same as before.
Other than that most changes of this (quite large) commit are straightforward.
its fields are initialized. Before:
t.swift:18:24: error: variable 'self.B' captured by a closure before being initialized
after:
t.swift:19:24: error: 'self' captured by a closure before all members were initialized
self.A.withCString { cString -> () in
^
t.swift:14:7: note: 'self.B' not initialized
var B: Int
^
This drives home the fact that 'self' is being captured here, not the individual
properties.
When a root class delegates to a non-class-bound protocol method, the self value
gets wrapped up in a SIL alloc_stack so it can be passed by address. Recognize
that the store involved is doing this, so we can provide a more specific diagnostic.
Before this, we produced:
variable 'self.x' used before being initialized
Now we produce:
error: use of 'self' in method call 'getg' before all stored properties are initialized
note: 'self.x' not initialized
Having a separate address and container value returned from alloc_stack is not really needed in SIL.
Even if they differ we have both addresses available during IRGen, because a dealloc_stack is always dominated by the corresponding alloc_stack in the same function.
Although this commit quite large, most changes are trivial. The largest non-trivial change is in IRGenSIL.
This commit is a NFC regarding the generated code. Even the generated SIL is the same (except removed #0, #1 and @local_storage).
(libraries now)
It has been generally agreed that we need to do this reorg, and now
seems like the perfect time. Some major pass reorganization is in the
works.
This does not have to be the final word on the matter. The consensus
among those working on the code is that it's much better than what we
had and a better starting point for future bike shedding.
Note that the previous organization was designed to allow separate
analysis and optimization libraries. It turns out this is an
artificial distinction and not an important goal.