The counterparts are:
UnownedRetain -> CopyValue.
UnownedRelease -> DestroyValue.
StrongRetainUnowned -> CopyUnownedValue.
I thought I hit all of these already. When I was fixing some DI stuff I realized
that I missed a few cases in SILGenLValue.cpp. To make sure we do not regress, I
added some verifier checks to make sure these instructions can only be used in
non-ownership sil.
rdar://31880847
The issue here is that the way the code was structured caused a large
conditional block at the beginning of the function that always exited early and
then a short unconditional block.
This commit inverts the if statement so that the short unconditional block is
now conditional and the large conditional block is unconditional, reducing the
overall indentation for the majority of the function.
conversions that reverse an implicit conversion done to align
foreign declarations with their imported types.
For example, consider an Objective-C method that returns an NSString*:
- (nonnull NSString*) foo;
This will be imported into Swift as a method returning a String:
func foo() -> String
A call to this method will implicitly convert the result to String
behind the scenes. If the user then casts the result back to NSString*,
that would normally be compiled as an additional conversion. The
compiler cannot simply eliminate the conversion because that is not
necessarily semantically equivalent.
This peephole recognizes as-casts that immediately reverse a bridging
conversion as a special case and gives them special power to eliminate
both conversions. For example, 'foo() as NSString' will simply return
the original return value. In addition to call results, this also
applies to call arguments, property accesses, and subscript accesses.
If we project an lvalue using a KeyPath, but the lvalue is only read from, we don't want to trigger writebacks, observers, or other side effects that a mutable projection would normally need to induce. Fixes SR-5338 | rdar://problem/33135489.
ground work for the syntactic bridging peephole.
- Pass source and dest formal types to the bridging routines in addition
to the dest lowered type. The dest lowered type is still necessary
in order to handle non-standard abstraction patterns for the dest type.
- Change bridging abstraction patterns to store bridged formal types
instead of the formal type.
- Improve how SIL type lowering deals with import-as-member patterns.
- Fix some AST bugs where inadequate information was being stored in
various expressions.
- Introduce the idea of a converting SGFContext and use it to regularize
the existing id-as-Any conversion peephole.
- Improve various places in SILGen to emit directly into contexts.
SILBuilder now tracks data dependencies between instructions
that open existentials and uses of the opened type, so
SILGen's mechanism for this is no longer needed.
In particular, this simplifies ArchetypeCalleeBuilder.
Adjust the definition of some diagnostics that are already called with
DeclBaseNames so that the implicit conversion from DeclBaseName to
Identifier is no longer needed.
Adjust the call side of diagnostics which don't have to deal with
special names to pass an Identifier to the diagnostic.
With the introduction of special decl names, `Identifier getName()` on
`ValueDecl` will be removed and pushed down to nominal declarations
whose name is guaranteed not to be special. Prepare for this by calling
to `DeclBaseName getBaseName()` instead where appropriate.
This changes `getBaseName()` on `DeclName` to return a `DeclBaseName`
instead of an `Identifier`. All places that will continue to be
expecting an `Identifier` are changed to call `getBaseIdentifier` which
will later assert that the `DeclName` is actually backed by an
identifier and not a special name.
For transitional purposes, a conversion operator from `DeclBaseName` to
`Identifier` has been added that will be removed again once migration
to DeclBaseName has been completed in other parts of the compiler.
Unify approach to printing declaration names
Printing a declaration's name using `<<` and `getBaseName()` is be
independent of the return type of `getBaseName()` which will change in
the future from `Identifier` to `DeclBaseName`
Printing a declaration's name using `<<` and `getBaseName()` is be
independent of the return type of `getBaseName()` which will change in
the future from `Identifier` to `DeclBaseName`
This is pretty awkward. If an lvalue has an open existential
as its RValue type, we would emit an alloc_stack instruction
holding the materialized temporary before we emitted the
value itself. This introduced a def-after-use violation
because the open existential type in the stack allocation
was not dominated by its definition.
To get around this, don't use an SGFContext to emit the 'get'
in-place. There's no performance degradation, because the only
time we will attempt materializing an lvalue with an open
existential type is when performing an lvalue access of a
class existential payload, and here we in-place initialization
makes no difference since the value is a single reference.
This is an LValue component whose value is the class
reference inside of a class existential.
Unlike OpenOpaqueExistentialComponent, this is a logical
component, with a "writeback" consisting of wrapping the
new class reference in a class existential having the
same conformances as the original.
This is slightly awkward, but adding "by-address" operations
on class existentials, and projecting the payload out is
a big change and might not make sense for other reasons.
When lowering a LoadExpr, SILGen constructs an LValue
and loads from it to produce an RValue.
If a LoadExpr contains another LoadExpr, the innermost
LoadExpr builds its own LValue, which is then loaded
to an RValue, and turned back into an LValue by creating
a single ValueComponent.
When evaluating an OpenExistentialExpr inside an LValue,
we record the base expression and evaluate it as an LValue
later when we encounter the corresponding OpaqueValueExpr.
The problem is when this is combined with a nested
LoadExpr, we might be inside of a different LValue than
the original LValue that contained the OpenExistentialExpr.
This would trigger an assertion, because the mapping from
OpaqueValueExprs to their base expressions was per-LValue;
instead, it needs to be per-SILGenFunction.
open-existential l-value during formal evaluation.
This causes unnecessarily conflicts for static enforcement, among
other potential problems.
rdar://32039566
Till now createApply, createTryApply, createPartialApply were taking some arguments like SubstCalleeType or ResultType. But these arguments are redundant and can be easily derived from other arguments of these functions. There is no need to put the burden of their computation on the clients of these APIs.
The removal of these redundant parameters simplifies the APIs and reduces the possibility of providing mismatched types by clients, which often happened in the past.
We're now double-diagnosing some things that are caught by both
SILGen and static enforcement; we can fix that later, but I want to
unblock this problem first.
The peephole causes the the formal access to the source and destination to
overlap. This results in unwanted exclusive access conflicts when assigning
from one struct stored property to another.
At John's suggestion I've added an isObviouslyNonConflicting() helper
method on LValue that tells when when it is safe to use the peephole
even when exclusivity enforcement enabled. For now, the helper is toothless. It
can be extended to claw back some of the peephole opportunities.
NFC by default.
I had a much more comprehensive version of this patch that I had to
back out in order to just get something in to unblock progress.
There's a lot of technical debt in SILGen around l-values.
Enabling this will almost certainly not get past the SIL passes.
UnpinPseudoComponent. NFC.
...this secondary use of LogicalLValueComponent for writebacks is
really a huge mess that I apologize for foisting on the world.
Exclusivity enforcement should eventually let us kill the awful
diagnoseWritebackConflict hack, which will make a simplification here
much easier.
Flip the polarity of the frontend flag controlling whether TSan treats inout
accesses as conceptual writes. It is now on by default. This lets TSan detect
racing mutating methods even when those methods are not themselves instrumented
(such as methods on Standard Library collections).
This behavior can be disabled by passing:
-Xfrontend -disable-tsan-inout-instrumentation
when compiling under TSan.
rdar://problem/31069963
(This re-applies #7736 with an update to the
tsan-inout.swift execution test to handle configurations where
TSan's ignore_interceptors_accesses is enabled by default.)
Add SILGen instrumentation to treat inout accesses as Thread Sanitizer writes.
The goal is to catch races on inout accesses even when there is a not an
llvm-level read/write to a particular address. Ultimately
this will enable TSan to, for example, report racy writes to distinct
stored properties of a common struct as a data race.
This instrumentation is off by default. It can be enabled with the
'enable-experimental-tsan-inout-instrumentation' frontend flag.
The high-level approach is to add a SIL-level builtin that represents a call
to a TSan routine in compiler-rt. Then, when emitting an address for an LValue
as part of an inout expression, we call this builtin for each path component
that represents an LValue. I've added an 'isRValue()' method to PathComponent
that tracks whether a component represents an RValue or an LValue. Right the
only PathComponent that sometimes returns 'true' is ValueComponent().
For now, we're instrumenting only InoutExprs, but in the future it probably
makes sense to instrument all LValue accesses. In this patch I've
added a 'TSanKind' parameter to SILGenFunction::emitAddressOfLValue() and
its helpers to limit instrumentation to inout accesses. I envision that this
parameter will eventually go away.