Skip to content

Commit

Permalink
[sending] Enable sending whenever region isolation is enabled and mak…
Browse files Browse the repository at this point in the history
…e SE-0430 an upcoming feature.

I also added support for expressing suppressable upcoming features.

rdar://128216574
  • Loading branch information
gottesmm committed May 18, 2024
1 parent 7592842 commit 20a3589
Show file tree
Hide file tree
Showing 16 changed files with 248 additions and 85 deletions.
28 changes: 18 additions & 10 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@
# endif
#endif

// A feature that's both suppressible and upcoming.
// Delegates to whichever the includer defines.
#ifndef SUPPRESSIBLE_UPCOMING_FEATURE
# if defined(SUPPRESSIBLE_UPCOMING_FEATURE) && \
defined(UPCOMING_FEATURE)
# error ambiguous defines when including Features.def
# elif defined(SUPPRESSIBLE_LANGUAGE_FEATURE)
# define SUPPRESSIBLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, #FeatureName)
# else
# define SUPPRESSIBLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
UPCOMING_FEATURE(FeatureName, SENumber, Version)
# endif
#endif

#ifndef SUPPRESSIBLE_LANGUAGE_FEATURE
# define SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
LANGUAGE_FEATURE(FeatureName, SENumber, Description)
Expand Down Expand Up @@ -198,6 +213,8 @@ UPCOMING_FEATURE(DynamicActorIsolation, 423, 6)
UPCOMING_FEATURE(NonfrozenEnumExhaustivity, 192, 6)
UPCOMING_FEATURE(GlobalActorIsolatedTypesUsability, 0434, 6)
UPCOMING_FEATURE(BorrowingSwitch, 432, 6)
UPCOMING_FEATURE(TransferringArgsAndResults, 430, 6)
SUPPRESSIBLE_UPCOMING_FEATURE(SendingArgsAndResults, 430, 6)

// Swift 7
UPCOMING_FEATURE(ExistentialAny, 335, 7)
Expand Down Expand Up @@ -352,16 +369,6 @@ EXPERIMENTAL_FEATURE(FixedArrays, true)
// Group Main Actor Isolation Errors by Scope
EXPERIMENTAL_FEATURE(GroupActorErrors, true)

// Allow for the 'transferring' keyword to be applied to arguments and results.
//
// Enables SendingArgsAndResults as well. After parsing, we just represent this
// as 'sendable' implying that since both are always enabled together, this
// doesn't need to be suppressed.
EXPERIMENTAL_FEATURE(TransferringArgsAndResults, true)

// Allow for the 'sending' keyword to be applied to arguments and results.
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(SendingArgsAndResults, true)

// Enable explicit isolation of closures.
EXPERIMENTAL_FEATURE(ClosureIsolation, true)

Expand Down Expand Up @@ -398,5 +405,6 @@ EXPERIMENTAL_FEATURE(DebugDescriptionMacro, true)
#undef CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE
#undef CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE
#undef SUPPRESSIBLE_EXPERIMENTAL_FEATURE
#undef SUPPRESSIBLE_UPCOMING_FEATURE
#undef SUPPRESSIBLE_LANGUAGE_FEATURE
#undef LANGUAGE_FEATURE
10 changes: 10 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -1357,6 +1357,16 @@ def disable_strict_concurrency_region_based_isolation : Flag<["-"],
HelpText<"Disable region based isolation when running with strict concurrency enabled. Only enabled with asserts">,
Flags<[HelpHidden]>;

def disable_transferring_args_and_results_with_region_isolation : Flag<["-"],
"disable-transferring-args-and-results-with-region-based-isolation">,
HelpText<"Disable transferring args and results when region based isolation is enabled. Only enabled with asserts">,
Flags<[HelpHidden]>;

def disable_sending_args_and_results_with_region_isolation : Flag<["-"],
"disable-sending-args-and-results-with-region-based-isolation">,
HelpText<"Disable sending args and results when region based isolation is enabled. Only enabled with asserts">,
Flags<[HelpHidden]>;

def no_scanner_module_validation: Flag<["-"], "no-scanner-module-validation">,
HelpText<"Do not validate binary modules in scanner and delegate the validation to swift-frontend">;
def module_load_mode: Separate<["-"], "module-load-mode">,
Expand Down
1 change: 1 addition & 0 deletions lib/ASTGen/Sources/ASTGen/SourceFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ extension Parser.ExperimentalFeatures {
mapFeature(.DoExpressions, to: .doExpressions)
mapFeature(.NonescapableTypes, to: .nonescapableTypes)
mapFeature(.TransferringArgsAndResults, to: .transferringArgsAndResults)
mapFeature(.SendingArgsAndResults, to: .sendingArgsAndResults)
}
}

Expand Down
19 changes: 19 additions & 0 deletions lib/DriverTool/sil_opt_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,17 @@ struct SILOptOptions {
"disable-region-based-isolation-with-strict-concurrency",
llvm::cl::init(false));

llvm::cl::opt<bool>
DisableTransferringArgsAndResultsWithRegionBasedIsolation = llvm::cl::opt<
bool>(
"disable-transferring-args-and-results-with-region-based-isolation",
llvm::cl::init(false));

llvm::cl::opt<bool> DisableSendingArgsAndResultsWithRegionBasedIsolation =
llvm::cl::opt<bool>(
"disable-sending-args-and-results-with-region-based-isolation",
llvm::cl::init(false));

llvm::cl::opt<std::string> SwiftVersionString = llvm::cl::opt<std::string>(
"swift-version",
llvm::cl::desc(
Expand Down Expand Up @@ -794,6 +805,14 @@ int sil_opt_main(ArrayRef<const char *> argv, void *MainAddr) {
Invocation.getLangOptions().enableFeature(Feature::RegionBasedIsolation);
}

if (Invocation.getLangOptions().hasFeature(Feature::RegionBasedIsolation)) {
if (!options.DisableTransferringArgsAndResultsWithRegionBasedIsolation)
Invocation.getLangOptions().enableFeature(
Feature::TransferringArgsAndResults);
if (!options.DisableSendingArgsAndResultsWithRegionBasedIsolation)
Invocation.getLangOptions().enableFeature(Feature::SendingArgsAndResults);
}

if (Invocation.getLangOptions().hasFeature(
Feature::TransferringArgsAndResults)) {
Invocation.getLangOptions().enableFeature(Feature::SendingArgsAndResults);
Expand Down
17 changes: 17 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,23 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.enableFeature(Feature::RegionBasedIsolation);
}

// Enable TransferringArgsAndResults/SendingArgsAndResults whenever
// RegionIsolation is enabled.
if (Opts.hasFeature(Feature::RegionBasedIsolation)) {
bool enableTransferringArgsAndResults = true;
bool enableSendingArgsAndResults = true;
#ifndef NDEBUG
enableTransferringArgsAndResults = !Args.hasArg(
OPT_disable_transferring_args_and_results_with_region_isolation);
enableSendingArgsAndResults = !Args.hasArg(
OPT_disable_sending_args_and_results_with_region_isolation);
#endif
if (enableTransferringArgsAndResults)
Opts.enableFeature(Feature::TransferringArgsAndResults);
if (enableSendingArgsAndResults)
Opts.enableFeature(Feature::SendingArgsAndResults);
}

// Enable SendingArgsAndResults whenever TransferringArgsAndResults is
// enabled.
//
Expand Down
9 changes: 5 additions & 4 deletions test/Concurrency/async_let_isolation.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -disable-region-based-isolation-with-strict-concurrency
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=targeted -disable-region-based-isolation-with-strict-concurrency
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -disable-region-based-isolation-with-strict-concurrency
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -verify-additional-prefix without-transferring-
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=targeted -verify-additional-prefix without-transferring-
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -disable-region-based-isolation-with-strict-concurrency -verify-additional-prefix without-transferring- -disable-transferring-args-and-results-with-region-based-isolation -disable-sending-args-and-results-with-region-based-isolation
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -disable-transferring-args-and-results-with-region-based-isolation -disable-sending-args-and-results-with-region-based-isolation -verify-additional-prefix without-transferring-
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete

// REQUIRES: concurrency
Expand All @@ -21,7 +22,7 @@ actor MyActor {
async let z = synchronous()

var localText = text
async let w = localText.removeLast() // expected-warning{{mutation of captured var 'localText' in concurrently-executing code}}
async let w = localText.removeLast() // expected-without-transferring-warning {{mutation of captured var 'localText' in concurrently-executing code}}

_ = await x
_ = await y
Expand Down
21 changes: 15 additions & 6 deletions test/Concurrency/global_actor_function_types.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
// RUN: %target-typecheck-verify-swift -disable-availability-checking
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=targeted
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -verify-additional-prefix complete-tns-
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -enable-upcoming-feature RegionBasedIsolation -verify-additional-prefix complete-tns-
// Typecheck.
// RUN: %target-typecheck-verify-swift -disable-availability-checking -verify-additional-prefix without-transferring-

// Emit SIL with minimal strict concurrency.
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -verify-additional-prefix without-transferring-

// Emit SIL with targeted concurrency.
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=targeted -verify-additional-prefix without-transferring-

// Emit SIL with strict concurrency + region based isolation but without transferring.
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -verify-additional-prefix complete-tns- -verify-additional-prefix without-transferring- -disable-transferring-args-and-results-with-region-based-isolation -disable-sending-args-and-results-with-region-based-isolation

// Emit SIL with strict concurrency + region based isolation + transferring
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -verify-additional-prefix complete-tns-

// REQUIRES: concurrency
// REQUIRES: asserts
Expand Down Expand Up @@ -323,7 +332,7 @@ func stripActor(_ expr: @Sendable @autoclosure () -> (() -> ())) async {

// NOTE: this warning is correct, but is only being caught by TypeCheckConcurrency's extra check.
@MainActor func exampleWhereConstraintSolverHasWrongDeclContext_v2() async -> Int {
async let a: () = noActor(mainActorFn) // expected-warning {{converting function value of type '@MainActor () -> ()' to '() -> ()' loses global actor 'MainActor'}}
async let a: () = noActor(mainActorFn) // expected-without-transferring-warning {{converting function value of type '@MainActor () -> ()' to '() -> ()' loses global actor 'MainActor'}}
await a
}

Expand Down
11 changes: 8 additions & 3 deletions test/Concurrency/issue-57376.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
// RUN: %target-swift-frontend -disable-availability-checking -strict-concurrency=targeted %s -emit-sil -o /dev/null -verify -verify-additional-prefix targeted-and-complete-
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -verify-additional-prefix targeted-and-complete-

// NOTE: We test separately with region isolation and region isolation +
// sending args and results since the semantics when sending args and
// results are enabled is different since async let in such a case takes a
// non-Sendable closure whose captures are transferred in while without it, we
// leave the async let closure as sendable and use sema level checking.
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -enable-upcoming-feature RegionBasedIsolation -verify-additional-prefix tns- -verify-additional-prefix no-transferring-tns-
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -enable-upcoming-feature RegionBasedIsolation -enable-experimental-feature TransferringArgsAndResults -verify-additional-prefix tns- -verify-additional-prefix transferring-tns-

// No transferring.
//
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -verify-additional-prefix tns- -verify-additional-prefix no-transferring-tns- -disable-transferring-args-and-results-with-region-based-isolation -disable-sending-args-and-results-with-region-based-isolation

// With transferring.
//
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -verify-additional-prefix tns- -verify-additional-prefix transferring-tns-

// REQUIRES: concurrency
// REQUIRES: asserts
Expand Down
93 changes: 93 additions & 0 deletions test/Concurrency/sending_conditional_suppression.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// RUN: %empty-directory(%t)

// RUN: %target-swift-frontend -enable-upcoming-feature SendingArgsAndResults -swift-version 5 -enable-library-evolution -module-name test -emit-module -o %t/test.swiftmodule -emit-module-interface-path - %s | %FileCheck %s

public class NonSendableKlass {}

// CHECK-LABEL: #if compiler(>=5.3) && $SendingArgsAndResults
// CHECK-NEXT: public func transferArgTest(_ x: sending test.NonSendableKlass)
// CHECK-NEXT: #else
// CHECK-NEXT: public func transferArgTest(_ x: test.NonSendableKlass)
// CHECK-NEXT: #endif
public func transferArgTest(_ x: sending NonSendableKlass) {}

// CHECK-LABEL: #if compiler(>=5.3) && $SendingArgsAndResults
// CHECK-NEXT: public func transferResultTest() -> sending test.NonSendableKlass
// CHECK-NEXT: #else
// CHECK-NEXT: public func transferResultTest() -> test.NonSendableKlass
// CHECK-NEXT: #endif
public func transferResultTest() -> sending NonSendableKlass { fatalError() }

// CHECK-LABEL: #if compiler(>=5.3) && $SendingArgsAndResults
// CHECK-NEXT: public func transferArgAndResultTest(_ x: test.NonSendableKlass, _ y: sending test.NonSendableKlass, _ z: test.NonSendableKlass) -> sending test.NonSendableKlass
// CHECK-NEXT: #else
// CHECK-NEXT: public func transferArgAndResultTest(_ x: test.NonSendableKlass, _ y: test.NonSendableKlass, _ z: test.NonSendableKlass) -> test.NonSendableKlass
// CHECK-NEXT: #endif
public func transferArgAndResultTest(_ x: NonSendableKlass, _ y: sending NonSendableKlass, _ z: NonSendableKlass) -> sending NonSendableKlass { fatalError() }

// CHECK-LABEL: #if compiler(>=5.3) && $SendingArgsAndResults
// CHECK-NEXT: public func argEmbeddedInType(_ fn: (sending test.NonSendableKlass) -> ())
// CHECK-NEXT: #else
// CHECK-NEXT: public func argEmbeddedInType(_ fn: (test.NonSendableKlass) -> ())
// CHECK-NEXT: #endif
public func argEmbeddedInType(_ fn: (sending NonSendableKlass) -> ()) {}

// CHECK-LABEL: #if compiler(>=5.3) && $SendingArgsAndResults
// CHECK-NEXT: public func resultEmbeddedInType(_ fn: () -> sending test.NonSendableKlass)
// CHECK-NEXT: #else
// CHECK-NEXT: public func resultEmbeddedInType(_ fn: () -> test.NonSendableKlass)
// CHECK-NEXT: #endif
public func resultEmbeddedInType(_ fn: () -> sending NonSendableKlass) {}

// CHECK-LABEL: #if compiler(>=5.3) && $SendingArgsAndResults
// CHECK-NEXT: public func argAndResultEmbeddedInType(_ fn: (test.NonSendableKlass, sending test.NonSendableKlass, test.NonSendableKlass) -> sending test.NonSendableKlass)
// CHECK-NEXT: #else
// CHECK-NEXT: public func argAndResultEmbeddedInType(_ fn: (test.NonSendableKlass, test.NonSendableKlass, test.NonSendableKlass) -> test.NonSendableKlass)
// CHECK-NEXT: #endif
public func argAndResultEmbeddedInType(_ fn: (NonSendableKlass, sending NonSendableKlass, NonSendableKlass) -> sending NonSendableKlass) {}

public class TestInKlass {
// CHECK-LABEL: #if compiler(>=5.3) && $SendingArgsAndResults
// CHECK-NEXT: public func testKlassArg(_ x: sending test.NonSendableKlass)
// CHECK-NEXT: #else
// CHECK-NEXT: public func testKlassArg(_ x: test.NonSendableKlass)
// CHECK-NEXT: #endif
public func testKlassArg(_ x: sending NonSendableKlass) { fatalError() }

// CHECK-LABEL: #if compiler(>=5.3) && $SendingArgsAndResults
// CHECK-NEXT: public func testKlassResult() -> sending test.NonSendableKlass
// CHECK-NEXT: #else
// CHECK-NEXT: public func testKlassResult() -> test.NonSendableKlass
// CHECK-NEXT: #endif
public func testKlassResult() -> sending NonSendableKlass { fatalError() }

// CHECK-LABEL: #if compiler(>=5.3) && $SendingArgsAndResults
// CHECK-NEXT: public func testKlassArgAndResult(_ x: test.NonSendableKlass, _ y: sending test.NonSendableKlass, z: test.NonSendableKlass) -> sending test.NonSendableKlass
// CHECK-NEXT: #else
// CHECK-NEXT: public func testKlassArgAndResult(_ x: test.NonSendableKlass, _ y: test.NonSendableKlass, z: test.NonSendableKlass) -> test.NonSendableKlass
// CHECK-NEXT: #endif
public func testKlassArgAndResult(_ x: NonSendableKlass, _ y: sending NonSendableKlass, z: NonSendableKlass) -> sending NonSendableKlass { fatalError() }
}

public struct TestInStruct {
// CHECK-LABEL: #if compiler(>=5.3) && $SendingArgsAndResults
// CHECK-NEXT: public func testKlassArg(_ x: sending test.NonSendableKlass)
// CHECK-NEXT: #else
// CHECK-NEXT: public func testKlassArg(_ x: test.NonSendableKlass)
// CHECK-NEXT: #endif
public func testKlassArg(_ x: sending NonSendableKlass) { fatalError() }

// CHECK-LABEL: #if compiler(>=5.3) && $SendingArgsAndResults
// CHECK-NEXT: public func testKlassResult() -> sending test.NonSendableKlass
// CHECK-NEXT: #else
// CHECK-NEXT: public func testKlassResult() -> test.NonSendableKlass
// CHECK-NEXT: #endif
public func testKlassResult() -> sending NonSendableKlass { fatalError() }

// CHECK-LABEL: #if compiler(>=5.3) && $SendingArgsAndResults
// CHECK-NEXT: public func testKlassArgAndResult(_ x: test.NonSendableKlass, _ y: sending test.NonSendableKlass, z: test.NonSendableKlass) -> sending test.NonSendableKlass
// CHECK-NEXT: #else
// CHECK-NEXT: public func testKlassArgAndResult(_ x: test.NonSendableKlass, _ y: test.NonSendableKlass, z: test.NonSendableKlass) -> test.NonSendableKlass
// CHECK-NEXT: #endif
public func testKlassArgAndResult(_ x: NonSendableKlass, _ y: sending NonSendableKlass, z: NonSendableKlass) -> sending NonSendableKlass { fatalError() }
}
2 changes: 1 addition & 1 deletion test/Concurrency/transfernonsendable.sil
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-sil-opt -transfer-non-sendable -enable-upcoming-feature RegionBasedIsolation -enable-experimental-feature TransferringArgsAndResults -strict-concurrency=complete %s -o /dev/null -verify
// RUN: %target-sil-opt -transfer-non-sendable -enable-upcoming-feature RegionBasedIsolation -enable-upcoming-feature TransferringArgsAndResults -strict-concurrency=complete %s -o /dev/null -verify

// REQUIRES: concurrency
// REQUIRES: asserts
Expand Down
Loading

0 comments on commit 20a3589

Please sign in to comment.