Otherwise, when multiple workers encounter a diagnostic simultaneously we can encounter races which lead to corrupted diagnostic data or crashes
Resolves rdar://159598539
I am going to be adding support to passes for emitting IsolationHistory behind a
flag. As part of this, we need to store the state of the partition that created
the error when the error is emitted. A partition stores heap memory so it makes
sense to make these types noncopyable types so we just move the heap memory
rather than copying it all over the place.
We want 'inout sending' parameters to have the semantics that not only are they
disconnected on return from the function but additionally they are guaranteed to
be in their own disconnected region on return. This implies that we must emit
errors when an 'inout sending' parameter or any element that is in the same
region as the current value within an 'inout sending' parameter is
returned. This commit contains a new diagnostic for RegionIsolation that adds
specific logic for detecting and emitting errors in these situations.
To implement this, we introduce 3 new diagnostics with each individual
diagnostic being slightly different to reflect the various ways that this error
can come up in source:
* Returning 'inout sending' directly:
```swift
func returnInOutSendingDirectly(_ x: inout sending NonSendableKlass) -> NonSendableKlass {
return x // expected-warning {{cannot return 'inout sending' parameter 'x' from global function 'returnInOutSendingDirectly'}}
// expected-note @-1 {{returning 'x' risks concurrent access since caller assumes that 'x' and the result of global function 'returnInOutSendingDirectly' can be safely sent to different isolation domains}}
}
```
* Returning a value in the same region as an 'inout sending' parameter. E.x.:
```swift
func returnInOutSendingRegionVar(_ x: inout sending NonSendableKlass) -> NonSendableKlass {
var y = x
y = x
return y // expected-warning {{cannot return 'y' from global function 'returnInOutSendingRegionVar'}}
// expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' since the caller assumes that 'x' and the result of global function 'returnInOutSendingRegionVar' can be safely sent to different isolation domains}}
}
```
* Returning the result of a function or computed property that is in the same
region as the 'inout parameter'.
```swift
func returnInOutSendingViaHelper(_ x: inout sending NonSendableKlass) -> NonSendableKlass {
let y = x
return useNonSendableKlassAndReturn(y) // expected-warning {{cannot return result of global function 'useNonSendableKlassAndReturn' from global function 'returnInOutSendingViaHelper'}}
// expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' since the caller assumes that 'x' and the result of global function 'returnInOutSendingViaHelper' can be safely sent to different isolation domains}}
}
```
Additionally, I had to introduce a specific variant for each of these
diagnostics for cases where due to us being in a method, we are actually in our
caller causing the 'inout sending' parameter to be in the same region as an
actor isolated value:
* Returning 'inout sending' directly:
```swift
extension MyActor {
func returnInOutSendingDirectly(_ x: inout sending NonSendableKlass) -> NonSendableKlass {
return x // expected-warning {{cannot return 'inout sending' parameter 'x' from instance method 'returnInOutSendingDirectly'}}
// expected-note @-1 {{returning 'x' risks concurrent access since caller assumes that 'x' is not actor-isolated and the result of instance method 'returnInOutSendingDirectly' is 'self'-isolated}}
}
}
```
* Returning a value in the same region as an 'inout sending' parameter. E.x.:
```swift
extension MyActor {
func returnInOutSendingRegionLet(_ x: inout sending NonSendableKlass) -> NonSendableKlass {
let y = x
return y // expected-warning {{cannot return 'y' from instance method 'returnInOutSendingRegionLet'}}
// expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' since the caller assumes that 'x' is not actor-isolated and the result of instance method 'returnInOutSendingRegionLet' is 'self'-isolated}}
}
}
```
* Returning the result of a function or computed property that is in the same region as the 'inout parameter'.
```swift
extension MyActor {
func returnInOutSendingViaHelper(_ x: inout sending NonSendableKlass) -> NonSendableKlass {
let y = x
return useNonSendableKlassAndReturn(y) // expected-warning {{cannot return result of global function 'useNonSendableKlassAndReturn' from instance method 'returnInOutSendingViaHelper'; this is an error in the Swift 6 language mode}}
// expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' since the caller assumes that 'x' is not actor-isolated and the result of instance method 'returnInOutSendingViaHelper' is 'self'-isolated}}
}
}
```
To implement this, I used two different approaches depending on whether or not
the returned value was generic or not.
* Concrete
In the case where we had a concrete value, I was able to in simple cases emit
diagnostics based off of the values returned by the return inst. In cases where
we phied together results due to multiple results in the same function, we
determine which of the incoming phied values caused the error by grabbing the
exit partition information of each of the incoming value predecessors and seeing
if an InOutSendingAtFunctionExit would emit an error.
* Generic
In the case of generic code, it is a little more interesting since the result is
a value stored in an our parameter instead of being a value directly returned by
a return inst. To work around this, I use PrunedLiveness to determine the last
values stored into the out parameter in the function to avoid having to do a
full dataflow. Then I take the exit blocks where we assign each of those values
and run the same check as we do in the direct phi case to emit the appropriate
error.
rdar://152454571
...to work around error building `unittests/runtime` on Linux.
`stdlib/include/llvm/Support` headers, a subset of
`llvm-project/llvm/include/llvm/Support`, are not compatible with the
latter.
Since we favor stdlib headers here, this makes sure Support headers will
not be transitively included through gtest, and helps to avoid mixed
includes, where a Support header existing only in LLVM is picked from
LLVM, whereas a Support header existing in both of the aforementioned
directories is picked from our stdlib.
This was used a long time ago for a design of a scanner which could rely on the client to specify that some modules *will be* present at a given location but are not yet during the scan. We have long ago determined that the scanner must have all modules available to it at the time of scan for soundness. This code has been stale for a couple of years and it is time to simplify things a bit by deleting it.
The diagnostic group documentation now point to the swift.org URL rather
than the toolchain path, so it no longer needs to be passed all the way
through sourcekitd.
Resolves rdar://151500502.
Previously there was still a sneaky hop which caused ordering issues.
This introduced a specific test startSynchronously_order which checks
that the task enqueues indeed are "immediate" and cleans up how we
handle this.
This also prepares for the being discussed in SE review direction of
this API that it SHOULD be ALLOWED to actually hop and NOT be
synchronous at all IF the isolation is specified on the closure and is
DIFFERENT than the callers dynamic isolation.
This effectively implements "synchronously run right now if dynamically
on the exact isolation as requested by the closure; otherwise enqueue
the task as usual".
resolves rdar://149284186
cc @drexin
https://github.com/swiftlang/swift/pull/79807 caused a regression in which
`AvailabilityContext` stopped tracking the available version range for the
active platform domain for certain platforms. Fix this by reverting to checking
`AvailabilityDomain::isActive()` to determine when a given platform
`AvailabilityDomain` represents the target platform. The compiler's existing
mapping from target triple to platform domain is incomplete and it's not clear
to me whether fixing that could cause other regressions.
Resolves rdar://147413616.
The exact cause of this is a mystery to me - each test case should be
finished (and thus any ASTs fully built) before the next runs/we exit.
But one of the recent failures contained a stacktrace:
```
...
20 [ra] 0x0000aaaad9d182f0 llvm::opt::OptTable::internalParseOneArg(llvm::opt::ArgList const&, unsigned int&, std::function<bool (llvm::opt::Option const&)>) const + 127 in SourceKitSwiftLangTests
21 [ra] 0x0000aaaad9d188d0 llvm::opt::OptTable::internalParseArgs(llvm::ArrayRef<char const*>, unsigned int&, unsigned int&, std::function<bool (llvm::opt::Option const&)>) const + 303 in SourceKitSwiftLangTests
22 [ra] 0x0000aaaad9d1877c llvm::opt::OptTable::ParseArgs(llvm::ArrayRef<char const*>, unsigned int&, unsigned int&, llvm::opt::Visibility) const + 47 in SourceKitSwiftLangTests
23 [ra] 0x0000aaaad6fad0d0 getLibcFileMapping[abi:cxx11](swift::ASTContext&, llvm::StringRef, std::optional<llvm::ArrayRef<llvm::StringRef> >, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> const&, bool) + 311 in SourceKitSwiftLangTests
24 [ra] 0x0000aaaad6fab304 swift::getClangInvocationFileMapping(swift::ASTContext&, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, bool) + 895 in SourceKitSwiftLangTests
25 [ra] 0x0000aaaad6f4dcac swift::ClangImporter::create(swift::ASTContext&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, swift::DependencyTracker*, swift::DWARFImporterDelegate*, bool) + 587 in SourceKitSwiftLangTests
26 [ra] 0x0000aaaad5ba07ac swift::CompilerInstance::setUpModuleLoaders() + 531 in SourceKitSwiftLangTests
27 [ra] 0x0000aaaad5ba0530 swift::CompilerInstance::setUpASTContextIfNeeded() + 447 in SourceKitSwiftLangTests
28 [ra] 0x0000aaaad5ba269c swift::CompilerInstance::setup(swift::CompilerInvocation const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, llvm::ArrayRef<char const*>) + 231 in SourceKitSwiftLangTests
29 [ra] 0x0000aaaad593d634 void SourceKit::WorkQueue::DispatchData::callAndDelete<(anonymous namespace)::ASTBuildOperation::schedule(SourceKit::WorkQueue)::$_11>(void*) + 2155 in SourceKitSwiftLangTests
30 [ra] 0x0000aaaad597c2fc executeBlock(void*) + 27 in SourceKitSwiftLangTests
31 [ra] 0x0000aaaad597c330 void* llvm::thread::ThreadProxy<std::tuple<void (*)(void*), void*> >(void*) + 27 in SourceKitSwiftLangTests
32 [ra] 0x0000ffffab37595c <unknown> in libc.so.6
```
So the assertion above clearly isn't true - we are definitely still
building an AST on exit here.
Regardless, this test is not worth CI failing as often as it is. Let's
disable it for now while we look into the cause.
`AvailabilityRange` is now being used as a currency type in more of the
compiler, and some of those uses are in permanent `ASTContext` allocations. The
class wraps the `VersionRange` utility, which is itself a wrapper around
`llvm::VersionTuple` with some additional storage for representing sentinel
values. Even though the two sentinel values can be be represented with just a
single bit of additional storage on top of the 16 bytes required to represent
`VersionTuple`, because of alignment requirements the sentinel values end up
bloating the layout of `VersionRange` by many bytes.
To make `AvailabilityRange` and `VersionRange` more efficient to store, we can
instead reserve two unlikely `llvm::VersionTuple` bit patterns as the sentinel
values instead. The values chosen are the same ones LLVM uses to represent
version tuple tombstones and empty keys in a `DenseMap`.
Introduce a constructor that takes an `llvm::VersionTuple` directly, instead of
needing to spell out `VersionRange::allGTE(<tuple>)` which is unnecessarily
verbose.