From f24ff98f9a62f800cf91a6ae6c08cc1247c8497b Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 25 Jun 2025 13:57:48 -0700 Subject: [PATCH 01/10] [nonisolated-nonsending] Make the AST not consider nonisolated(nonsending) to be an actor isolation crossing point. We were effectively working around this previously at the SIL level. This caused us not to obey the semantics of the actual evolution proposal. As an example of this, in the following, x should not be considered main actor isolated: ```swift nonisolated(nonsending) func useValue(_ t: T) async {} @MainActor func test() async { let x = NS() await useValue(x) print(x) } ``` we should just consider this to be a merge and since useValue does not have any MainActor isolated parameters, x should not be main actor isolated and we should not emit an error here. I also fixed a separate issue where we were allowing for parameters of nonisolated(nonsending) functions to be passed to @concurrent functions. We cannot allow for this to happen since the nonisolated(nonsending) parameters /could/ be actor isolated. Of course, we have lost that static information at this point so we cannot allow for it. Given that we have the actual dynamic actor isolation information, we could dynamically allow for the parameters to be passed... but that is something that is speculative and is definitely outside of the scope of this patch. rdar://154139237 (cherry picked from commit c12c99fb734b7d9b9ba36c58956b5aa1f74ff4ba) --- lib/SILOptimizer/Utils/SILIsolationInfo.cpp | 27 ++- lib/Sema/TypeCheckConcurrency.cpp | 44 ++-- .../Inputs/regionbasedisolation.h | 3 + test/ClangImporter/regionbasedisolation.swift | 39 +++- .../nonisolated_inherits_isolation.swift | 201 ++++++++++++++++-- 5 files changed, 283 insertions(+), 31 deletions(-) diff --git a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp index cfe3b918682ef..05da96f60ed37 100644 --- a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp +++ b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp @@ -447,6 +447,21 @@ SILIsolationInfo SILIsolationInfo::get(SILInstruction *inst) { return info; } + // See if our function apply site has an implicit isolated parameter. In + // such a case, we know that we have a caller inheriting isolated + // function. Return that this has disconnected isolation. + // + // DISCUSSION: The reason why we are doing this is that we already know that + // the AST is not going to label this as an isolation crossing point so we + // will only perform a merge. We want to just perform an isolation merge + // without adding additional isolation info. Otherwise, a nonisolated + // function that + if (auto paramInfo = fas.getSubstCalleeType()->maybeGetIsolatedParameter(); + paramInfo && paramInfo->hasOption(SILParameterInfo::ImplicitLeading) && + paramInfo->hasOption(SILParameterInfo::Isolated)) { + return SILIsolationInfo::getDisconnected(false /*unsafe nonisolated*/); + } + if (auto *isolatedOp = fas.getIsolatedArgumentOperandOrNullPtr()) { // First look through ActorInstance agnostic values so we can find the // type of the actual underlying actor (e.x.: copy_value, @@ -539,9 +554,8 @@ SILIsolationInfo SILIsolationInfo::get(SILInstruction *inst) { if (actorInstance) { if (auto actualIsolatedValue = ActorInstance::getForValue(actorInstance)) { - // See if we have a function parameter. In that case, we want to see - // if we have a function argument. In such a case, we need to use - // the right parameter and the var decl. + // See if we have a function parameter. In such a case, we need to + // use the right parameter and the var decl. if (auto *fArg = dyn_cast( actualIsolatedValue.getValue())) { if (auto info = @@ -985,6 +999,13 @@ SILIsolationInfo SILIsolationInfo::get(SILArgument *arg) { // handles isolated self and specifically marked isolated. if (auto *isolatedArg = llvm::cast_or_null( fArg->getFunction()->maybeGetIsolatedArgument())) { + // See if the function is nonisolated(nonsending). In such a case, return + // task isolated. + if (auto funcIsolation = fArg->getFunction()->getActorIsolation(); + funcIsolation && funcIsolation->isCallerIsolationInheriting()) { + return SILIsolationInfo::getTaskIsolated(fArg); + } + auto astType = isolatedArg->getType().getASTType(); if (astType->lookThroughAllOptionalTypes()->getAnyActor()) { return SILIsolationInfo::getActorInstanceIsolated(fArg, isolatedArg); diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 97a0927f7c843..c648c6a3c62e2 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4067,6 +4067,10 @@ namespace { Expr *argForIsolatedParam = nullptr; auto calleeDecl = apply->getCalledValue(/*skipFunctionConversions=*/true); + if (calleeDecl && + calleeDecl->getAttrs().hasAttribute()) + return false; + auto fnTypeIsolation = fnType->getIsolation(); if (fnTypeIsolation.isGlobalActor()) { // If the function type is global-actor-qualified, determine whether @@ -4112,10 +4116,6 @@ namespace { calleeDecl = memberRef->first.getDecl(); argForIsolatedParam = selfApplyFn->getBase(); } - } else if (calleeDecl && - calleeDecl->getAttrs() - .hasAttribute()) { - return false; } // Check for isolated parameters. @@ -4166,11 +4166,25 @@ namespace { break; } - // If we're calling an async function that's nonisolated, and we're in - // an isolated context, then we're exiting the actor context. - if (mayExitToNonisolated && fnType->isAsync() && - getContextIsolation().isActorIsolated()) - unsatisfiedIsolation = ActorIsolation::forNonisolated(/*unsafe=*/false); + // If we're calling an async function that's nonisolated, and we're in an + // isolated context, then we're exiting the actor context unless we have + // nonisolated(nonsending) isolation. + // + // NOTE: We do not check fnTypeIsolation since that is the AST level + // actual isolation which does not have nonisolated(nonsending) added to + // it yet. Instead, we want the direct callee including casts since those + // casts is what would add the nonisolated(nonsending) bit to the function + // type isolation. + if (mayExitToNonisolated && fnType->isAsync()) { + if (getContextIsolation().isActorIsolated() && + !fnTypeIsolation.isNonIsolatedCaller()) + unsatisfiedIsolation = + ActorIsolation::forNonisolated(/*unsafe=*/false); + else if (getContextIsolation().isCallerIsolationInheriting() && + fnTypeIsolation.isNonIsolated()) + unsatisfiedIsolation = + ActorIsolation::forNonisolated(/*unsafe=*/false); + } // If there was no unsatisfied actor isolation, we're done. if (!unsatisfiedIsolation) @@ -8129,12 +8143,14 @@ ActorReferenceResult ActorReferenceResult::forReference( // When the declaration is not actor-isolated, it can always be accessed // directly. if (!declIsolation.isActorIsolated()) { + if (declRef.getDecl()->getAttrs().hasAttribute()) + return forSameConcurrencyDomain(declIsolation, options); + // If the declaration is asynchronous and we are in an actor-isolated - // context (of any kind), then we exit the actor to the nonisolated context. - if (decl->isAsync() && contextIsolation.isActorIsolated() && - !declRef.getDecl() - ->getAttrs() - .hasAttribute()) + // context (of any kind) or it is a caller isolation inheriting, then + // we exit the actor to the nonisolated context. + if (decl->isAsync() && (contextIsolation.isActorIsolated() || + contextIsolation.isCallerIsolationInheriting())) return forExitsActorToNonisolated(contextIsolation, options); // Otherwise, we stay in the same concurrency domain, whether on an actor diff --git a/test/ClangImporter/Inputs/regionbasedisolation.h b/test/ClangImporter/Inputs/regionbasedisolation.h index 7852358ca5a3e..6385570570d3e 100644 --- a/test/ClangImporter/Inputs/regionbasedisolation.h +++ b/test/ClangImporter/Inputs/regionbasedisolation.h @@ -13,6 +13,9 @@ NS_ASSUME_NONNULL_BEGIN (void (^)(NSArray *_Nullable, NSError *_Nullable))completionHandler; +- (void)useValue:(id)object + withCompletionHandler:(void (^)(NSObject *_Nullable))completionHandler; + @end NS_ASSUME_NONNULL_END diff --git a/test/ClangImporter/regionbasedisolation.swift b/test/ClangImporter/regionbasedisolation.swift index 63a2364dafbb2..f754a5e66b8f4 100644 --- a/test/ClangImporter/regionbasedisolation.swift +++ b/test/ClangImporter/regionbasedisolation.swift @@ -1,4 +1,5 @@ -// RUN: %target-swift-frontend %s -import-objc-header %S/Inputs/regionbasedisolation.h -verify -c -swift-version 6 +// RUN: %target-swift-frontend %s -import-objc-header %S/Inputs/regionbasedisolation.h -verify -verify-additional-prefix ni- -c -swift-version 6 +// RUN: %target-swift-frontend %s -import-objc-header %S/Inputs/regionbasedisolation.h -verify -verify-additional-prefix ni-ns- -c -swift-version 6 -enable-upcoming-feature NonisolatedNonsendingByDefault // RUN: %target-swift-frontend %s -import-objc-header %S/Inputs/regionbasedisolation.h -emit-silgen -swift-version 6 | %FileCheck %s // REQUIRES: objc_interop @@ -123,3 +124,39 @@ extension ObjCObject { try await loadObjects2() } // expected-error {{task or actor isolated value cannot be sent}} } + +@concurrent func useValueConcurrently(_ t: T) async {} +@MainActor func useValueMainActor(_ t: T) async {} +nonisolated(nonsending) func useValueNonIsolatedNonSending(_ t: T) async {} + +@MainActor func testMainActorMerging(_ y: NSObject) async { + let x = ObjCObject() + await x.useValue(y) + await useValueConcurrently(x) // expected-error {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending main actor-isolated 'x' to nonisolated global function 'useValueConcurrently' risks causing data races between nonisolated and main actor-isolated uses}} +} + +func testTaskLocal(_ y: NSObject) async { + let x = ObjCObject() + await x.useValue(y) + await useValueConcurrently(x) // expected-ni-ns-error {{sending 'x' risks causing data races}} + // expected-ni-ns-note @-1 {{sending task-isolated 'x' to nonisolated global function 'useValueConcurrently' risks causing data races between nonisolated and task-isolated uses}} + + // This is not safe since we merge x into y's region making x task + // isolated. We then try to send it to a main actor function. + await useValueMainActor(x) // expected-error {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending task-isolated 'x' to main actor-isolated global function 'useValueMainActor' risks causing data races between main actor-isolated and task-isolated uses}} +} + +actor MyActor { + var field = NSObject() + + // This is safe since x.useValue is going to be nonisolated(nonsending) so we + // are going to merge x into the actor. And useValueNonIsolatedNonSending + // inherits from the context. + func test() async { + let x = ObjCObject() + await x.useValue(field) + await useValueNonIsolatedNonSending(x) + } +} diff --git a/test/Concurrency/nonisolated_inherits_isolation.swift b/test/Concurrency/nonisolated_inherits_isolation.swift index ec1e6d8211d84..b12f2de7bc905 100644 --- a/test/Concurrency/nonisolated_inherits_isolation.swift +++ b/test/Concurrency/nonisolated_inherits_isolation.swift @@ -13,7 +13,12 @@ // Declarations // ////////////////// -class NonSendableKlass {} +class NonSendableKlass { + func unspecifiedCaller() async {} + nonisolated func nonisolatedCaller() async {} + nonisolated(nonsending) func nonisolatedNonSendingCaller() async {} + @concurrent func concurrentCaller() async {} +} nonisolated class NonIsolatedNonSendableKlass { func unspecifiedMethod() async {} @@ -24,6 +29,8 @@ func unspecifiedSyncUse(_ t: T) {} func unspecifiedAsyncUse(_ t: T) async {} nonisolated func nonisolatedSyncUse(_ t: T) {} nonisolated func nonisolatedAsyncUse(_ t: T) async {} +nonisolated(nonsending) func nonisolatedNonSendingAsyncUse(_ t: T) async {} +@concurrent func concurrentAsyncUse(_ t: T) async {} func unspecifiedSyncUseWithResult(_ t: T) -> T { t } func unspecifiedAsyncUseWithResult(_ t: T) async -> T { t } @@ -34,6 +41,8 @@ func unspecifiedSyncResult() -> NonSendableKlass { fatalError() } func unspecifiedAsyncResult() async -> NonSendableKlass { fatalError() } nonisolated func nonisolatedSyncResult() -> NonSendableKlass { fatalError() } nonisolated func nonisolatedAsyncResult() async -> NonSendableKlass { fatalError() } +func sendingParameter(_ t: sending T) async {} +func useValue(_ t: T) {} @MainActor func sendToMain(_ t: T) async {} @@ -49,6 +58,13 @@ struct CustomActor { @CustomActor func sendToCustom(_ t: T) async {} +@MainActor +final class MainActorKlass { + var ns = NonSendableKlass() + + func useValueAsync(_ x: NonSendableKlass) async {} +} + /////////// // Tests // /////////// @@ -90,22 +106,17 @@ actor ActorTest { await sendToMain(x1) let x2 = await unspecifiedAsyncResult() - await sendToMain(x2) // expected-enabled-error {{sending 'x2' risks causing data races}} - // expected-enabled-note @-1 {{sending 'self'-isolated 'x2' to main actor-isolated global function 'sendToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}} + await sendToMain(x2) let x3 = nonisolatedSyncResult() await sendToMain(x3) let x4 = await nonisolatedAsyncResult() - await sendToMain(x4) // expected-enabled-error {{sending 'x4' risks causing data races}} - // expected-enabled-note @-1 {{sending 'self'-isolated 'x4' to main actor-isolated global function 'sendToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}} + await sendToMain(x4) } } -@MainActor -class MainActorKlass { - var ns = NonSendableKlass() - +extension MainActorKlass { func callNonIsolatedWithParam() async { unspecifiedSyncUse(ns) await unspecifiedAsyncUse(ns) // expected-disabled-error {{sending 'self.ns' risks causing data races}} @@ -141,15 +152,13 @@ class MainActorKlass { await sendToCustom(x1) let x2 = await unspecifiedAsyncResult() - await sendToCustom(x2) // expected-enabled-error {{sending 'x2' risks causing data races}} - // expected-enabled-note @-1 {{sending main actor-isolated 'x2' to global actor 'CustomActor'-isolated global function 'sendToCustom' risks causing data races between global actor 'CustomActor'-isolated and main actor-isolated uses}} + await sendToCustom(x2) let x3 = nonisolatedSyncResult() await sendToCustom(x3) let x4 = await nonisolatedAsyncResult() - await sendToCustom(x4) // expected-enabled-error {{sending 'x4' risks causing data races}} - // expected-enabled-note @-1 {{sending main actor-isolated 'x4' to global actor 'CustomActor'-isolated global function 'sendToCustom' risks causing data races between global actor 'CustomActor'-isolated and main actor-isolated uses}} + await sendToCustom(x4) } } @@ -166,3 +175,169 @@ func validateNonisolatedOnClassMeansCallerIsolationInheritingOnFuncDecl( await c.nonisolatedMethod() // expected-disabled-error {{sending 'c' risks causing data races}} // expected-disabled-note @-1 {{sending main actor-isolated 'c' to nonisolated instance method 'nonisolatedMethod()' risks causing data races between nonisolated and main actor-isolated uses}} } + +// Shouldn't get an error here since we are not using after we send to main. +func nonisolatedCallingNonIsolated() async { + let c = NonSendableKlass() + + await unspecifiedAsyncUse(c) + await unspecifiedAsyncUse(c) + + await sendToMain(c) +} + +func nonisolatedCallingNonIsolated2() async { + let c = NonSendableKlass() + + await unspecifiedAsyncUse(c) + await unspecifiedAsyncUse(c) + + await sendToMain(c) // expected-error {{sending 'c' risks causing data races}} + // expected-note @-1 {{sending 'c' to main actor-isolated global function 'sendToMain' risks causing data races between main actor-isolated and local nonisolated uses}} + + await unspecifiedAsyncUse(c) // expected-note {{access can happen concurrently}} +} + +// We should emit an error here despite the function context being @MainActor. +@MainActor +func sendingWithMainActor() async { + let c = NonSendableKlass() + await sendingParameter(c) // expected-error {{sending 'c' risks causing data races}} + // expected-note @-1 {{'c' used after being passed as a 'sending' parameter}} + useValue(c) // expected-note {{access can happen concurrently}} +} + +// We should emit an error here despite the function context have an explicit +// isolated parameter. +func sendingWithIsolatedParam(_ a: isolated Optional) async { + let c = NonSendableKlass() + await sendingParameter(c) // expected-error {{sending 'c' risks causing data races}} + // expected-note @-1 {{'c' used after being passed as a 'sending' parameter}} + useValue(c) // expected-note {{access can happen concurrently}} +} + +// This errors only when disabled since the first time we call +// unspecifiedAsyncUse we have a disconnected value and the second time we have +// a value in a main actor isolated region and the unspecifiedAsyncUse runs on +// the main actor. +// +// TODO: This doesn't error if we have a non-final class because of a known bug +// where we infer isolation wrong for non-final class setters. That is why +// MainActorKlass is made final so we can test this appropriately. +@MainActor +func testUnrolledLoop(_ a: MainActorKlass) async { + let k = NonSendableKlass() + await unspecifiedAsyncUse(k) + a.ns = k + await unspecifiedAsyncUse(k) // expected-disabled-error {{sending 'k' risks causing data races}} + // expected-disabled-note @-1 {{sending main actor-isolated 'k' to nonisolated global function 'unspecifiedAsyncUse' risks causing data races between nonisolated and main actor-isolated uses}} +} + +// We emit an error in both modes since we are now in an @MainActor isolated +// function. +func testUnrolledLoop2(_ a: MainActorKlass) async { + let k = NonSendableKlass() + await unspecifiedAsyncUse(k) + await a.useValueAsync(k) // expected-error {{sending 'k' risks causing data races}} + // expected-note @-1 {{sending 'k' to main actor-isolated instance method 'useValueAsync' risks causing data races between main actor-isolated and local nonisolated uses}} + await unspecifiedAsyncUse(k) // expected-note {{access can happen concurrently}} +} + +func testUnrolledLoopWithAsyncLet(_ a: MainActorKlass) async { + let k = NonSendableKlass() + await unspecifiedAsyncUse(k) + // This is valid since our valid is disconnected here. + async let value: () = await unspecifiedAsyncUse(k) + _ = await value + + await a.useValueAsync(k) // expected-error {{sending 'k' risks causing data races}} + // expected-note @-1 {{sending 'k' to main actor-isolated instance method 'useValueAsync' risks causing data races between main actor-isolated and local nonisolated uses}} + async let value2: () = await unspecifiedAsyncUse(k) // expected-note {{access can happen concurrently}} + _ = await value2 +} + +@MainActor +func testUnrolledLoopWithAsyncLet2(_ a: MainActorKlass) async { + let k = NonSendableKlass() + await unspecifiedAsyncUse(k) + // This is valid since our valid is disconnected here. + async let value: () = await unspecifiedAsyncUse(k) + _ = await value + + await a.useValueAsync(k) + async let value2: () = await unspecifiedAsyncUse(k) // expected-error {{sending 'k' risks causing data races}} + // expected-note @-1 {{sending main actor-isolated 'k' into async let risks causing data races between nonisolated and main actor-isolated uses}} + _ = await value2 +} + +@MainActor +func testUnrolledLoopWithAsyncLet3(_ a: MainActorKlass) async { + let k = NonSendableKlass() + await unspecifiedAsyncUse(k) + // This is valid since our valid is disconnected here. + async let value: () = await unspecifiedAsyncUse(k) + _ = await value + + await a.useValueAsync(k) + async let value2: () = await sendToMain(k) // expected-error {{sending 'k' risks causing data races}} + // expected-note @-1 {{sending main actor-isolated 'k' into async let risks causing data races between nonisolated and main actor-isolated uses}} + _ = await value2 +} + +func unspecifiedCallingVariousNonisolated(_ x: NonSendableKlass) async { + await x.unspecifiedCaller() + await x.nonisolatedCaller() + await x.nonisolatedNonSendingCaller() + await x.concurrentCaller() // expected-enabled-error {{sending 'x' risks causing data races}} + // expected-enabled-note @-1 {{sending task-isolated 'x' to nonisolated instance method 'concurrentCaller()' risks causing data races between nonisolated and task-isolated uses}} + + await unspecifiedAsyncUse(x) + await nonisolatedAsyncUse(x) + await nonisolatedNonSendingAsyncUse(x) + await concurrentAsyncUse(x) // expected-enabled-error {{sending 'x' risks causing data races}} + // expected-enabled-note @-1 {{sending task-isolated 'x' to nonisolated global function 'concurrentAsyncUse' risks causing data races between nonisolated and task-isolated uses}} +} + +nonisolated func nonisolatedCallingVariousNonisolated(_ x: NonSendableKlass) async { + await x.unspecifiedCaller() + await x.nonisolatedCaller() + await x.nonisolatedNonSendingCaller() + await x.concurrentCaller() // expected-enabled-error {{sending 'x' risks causing data races}} + // expected-enabled-note @-1 {{sending task-isolated 'x' to nonisolated instance method 'concurrentCaller()' risks causing data races between nonisolated and task-isolated uses}} + + await unspecifiedAsyncUse(x) + await nonisolatedAsyncUse(x) + await nonisolatedNonSendingAsyncUse(x) + await concurrentAsyncUse(x) // expected-enabled-error {{sending 'x' risks causing data races}} + // expected-enabled-note @-1 {{sending task-isolated 'x' to nonisolated global function 'concurrentAsyncUse' risks causing data races between nonisolated and task-isolated uses}} +} + +nonisolated(nonsending) func nonisolatedNonSendingCallingVariousNonisolated(_ x: NonSendableKlass) async { + await x.unspecifiedCaller() // expected-disabled-error {{sending 'x' risks causing data races}} + // expected-disabled-note @-1 {{sending task-isolated 'x' to nonisolated instance method 'unspecifiedCaller()' risks causing data races between nonisolated and task-isolated uses}} + await x.nonisolatedCaller() // expected-disabled-error {{sending 'x' risks causing data races}} + // expected-disabled-note @-1 {{sending task-isolated 'x' to nonisolated instance method 'nonisolatedCaller()' risks causing data races between nonisolated and task-isolated uses}} + await x.nonisolatedNonSendingCaller() + await x.concurrentCaller() // expected-error {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending task-isolated 'x' to nonisolated instance method 'concurrentCaller()' risks causing data races between nonisolated and task-isolated uses}} + + await unspecifiedAsyncUse(x) // expected-disabled-error {{sending 'x' risks causing data races}} + // expected-disabled-note @-1 {{sending task-isolated 'x' to nonisolated global function 'unspecifiedAsyncUse' risks causing data races between nonisolated and task-isolated uses}} + await nonisolatedAsyncUse(x) // expected-disabled-error {{sending 'x' risks causing data races}} + // expected-disabled-note @-1 {{sending task-isolated 'x' to nonisolated global function 'nonisolatedAsyncUse' risks causing data races between nonisolated and task-isolated uses}} + await nonisolatedNonSendingAsyncUse(x) + await concurrentAsyncUse(x) // expected-error {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending task-isolated 'x' to nonisolated global function 'concurrentAsyncUse' risks causing data races between nonisolated and task-isolated uses}} +} + +@concurrent func concurrentCallingVariousNonisolated(_ x: NonSendableKlass) async { + await x.unspecifiedCaller() + await x.nonisolatedCaller() + await x.nonisolatedNonSendingCaller() + await x.concurrentCaller() + + await unspecifiedAsyncUse(x) + await nonisolatedAsyncUse(x) + await nonisolatedNonSendingAsyncUse(x) + await concurrentAsyncUse(x) +} From 065ffa3b721b9d2994184ada4ca1e4f4bedcfa57 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 25 Jun 2025 14:23:27 -0700 Subject: [PATCH 02/10] [rbi] Convert all rbi tests to run also in NonisolatedNonsendingByDefault. Going to update the tests in the next commit. This just makes it easier to review. (cherry picked from commit a6edf4fb909832fce5db8e364f8d1f346dbf9615) --- test/ClangImporter/regionbasedisolation.swift | 1 + .../concurrent_value_checking.swift | 4 +- .../concurrent_value_checking_objc.swift | 4 +- test/Concurrency/sendable_checking.swift | 69 ++++++++++++------- test/Concurrency/transfernonsendable.swift | 32 +++++---- .../transfernonsendable_asynclet.swift | 2 + ...e_closureliterals_isolationinference.swift | 21 +++--- ...ransfernonsendable_functionsubtyping.swift | 2 + .../transfernonsendable_global_actor.swift | 36 +++++----- ...nonsendable_global_actor_nonsendable.swift | 2 + ...sfernonsendable_global_actor_sending.swift | 4 ++ ...nsfernonsendable_global_actor_swift6.swift | 24 ++++--- .../transfernonsendable_initializers.swift | 2 + ...dable_isolationcrossing_partialapply.swift | 2 + .../transfernonsendable_nonisolated.swift | 2 + ...ransfernonsendable_nonisolatedunsafe.swift | 2 + .../transfernonsendable_objc.swift | 5 +- .../transfernonsendable_ownership.swift | 2 + .../transfernonsendable_preconcurrency.swift | 2 + ...ernonsendable_preconcurrency_sending.swift | 2 + .../transfernonsendable_rbi_result.swift | 25 ++++++- ...nonsendable_region_based_sendability.swift | 2 + .../transfernonsendable_sending_params.swift | 4 +- .../transfernonsendable_sending_results.swift | 2 + .../transfernonsendable_typed_errors.swift | 2 + ...rnonsendable_unavailable_conformance.swift | 5 +- ...sfernonsendable_warning_until_swift6.swift | 2 + 27 files changed, 177 insertions(+), 85 deletions(-) diff --git a/test/ClangImporter/regionbasedisolation.swift b/test/ClangImporter/regionbasedisolation.swift index f754a5e66b8f4..41b1fc3de29db 100644 --- a/test/ClangImporter/regionbasedisolation.swift +++ b/test/ClangImporter/regionbasedisolation.swift @@ -3,6 +3,7 @@ // RUN: %target-swift-frontend %s -import-objc-header %S/Inputs/regionbasedisolation.h -emit-silgen -swift-version 6 | %FileCheck %s // REQUIRES: objc_interop +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault extension ObjCObject { // CHECK-LABEL: sil hidden [ossa] @$sSo10ObjCObjectC20regionbasedisolationE11sendObjectsSaySo8NSObjectCGyYaKF : $@convention(method) @async (@guaranteed ObjCObject) -> (@sil_sending @owned Array, @error any Error) { diff --git a/test/Concurrency/concurrent_value_checking.swift b/test/Concurrency/concurrent_value_checking.swift index 0738d4ea0dd0a..7dc503268a0d3 100644 --- a/test/Concurrency/concurrent_value_checking.swift +++ b/test/Concurrency/concurrent_value_checking.swift @@ -1,9 +1,11 @@ // RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify -DALLOW_TYPECHECKER_ERRORS -verify-additional-prefix typechecker- -verify-additional-prefix tns-allow-typechecker- -// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify -verify-additional-prefix tns- +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify -verify-additional-prefix tns-ni- -verify-additional-prefix tns- +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify -verify-additional-prefix tns-ni-ns- -verify-additional-prefix tns- -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault class NotConcurrent { } // expected-note 12{{class 'NotConcurrent' does not conform to the 'Sendable' protocol}} // expected-tns-allow-typechecker-note @-1 {{class 'NotConcurrent' does not conform to the 'Sendable' protocol}} diff --git a/test/Concurrency/concurrent_value_checking_objc.swift b/test/Concurrency/concurrent_value_checking_objc.swift index a08c6a3ebb2bc..5b16ce46233de 100644 --- a/test/Concurrency/concurrent_value_checking_objc.swift +++ b/test/Concurrency/concurrent_value_checking_objc.swift @@ -1,8 +1,10 @@ -// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete %s -emit-sil -o /dev/null -verify +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete %s -emit-sil -o /dev/null -verify -verify-additional-prefix ni- +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete %s -emit-sil -o /dev/null -verify -verify-additional-prefix ni-ns- -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: objc_interop // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault import Foundation diff --git a/test/Concurrency/sendable_checking.swift b/test/Concurrency/sendable_checking.swift index 3ffdc6b7a206a..9b9a96103cc43 100644 --- a/test/Concurrency/sendable_checking.swift +++ b/test/Concurrency/sendable_checking.swift @@ -1,9 +1,11 @@ -// RUN: %target-swift-frontend -target %target-swift-5.0-abi-triple -verify -strict-concurrency=targeted -verify-additional-prefix targeted- -emit-sil -o /dev/null %s -// RUN: %target-swift-frontend -target %target-swift-5.0-abi-triple -verify -strict-concurrency=complete -verify-additional-prefix tns- -verify-additional-prefix complete-and-tns- -emit-sil -o /dev/null %s +// RUN: %target-swift-frontend -target %target-swift-5.0-abi-triple -verify -verify-additional-prefix targeted-and-ni- -strict-concurrency=targeted -verify-additional-prefix targeted- -emit-sil -o /dev/null %s +// RUN: %target-swift-frontend -target %target-swift-5.0-abi-triple -verify -strict-concurrency=complete -verify-additional-prefix tns-ni- -verify-additional-prefix tns- -emit-sil -o /dev/null %s -swift-version 5 -verify-additional-prefix targeted-and-ni- +// RUN: %target-swift-frontend -target %target-swift-5.0-abi-triple -verify -strict-concurrency=complete -verify-additional-prefix tns-ni-ns- -verify-additional-prefix tns- -emit-sil -o /dev/null %s -enable-upcoming-feature NonisolatedNonsendingByDefault -swift-version 5 -DNONISOLATEDNONSENDING // REQUIRES: concurrency // REQUIRES: asserts // REQUIRES: OS=macosx +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault @available(SwiftStdlib 5.1, *) struct NS1 { } @@ -15,7 +17,7 @@ extension NS1: Sendable { } @available(SwiftStdlib 5.1, *) struct NS2 { // expected-note {{consider making struct 'NS2' conform to the 'Sendable' protocol}} - // expected-complete-and-tns-note @-1 {{consider making struct 'NS2' conform to the 'Sendable' protocol}} + // expected-tns-note @-1 {{consider making struct 'NS2' conform to the 'Sendable' protocol}} var ns1: NS1 } @@ -27,7 +29,7 @@ extension NS3: Sendable { } @available(SwiftStdlib 5.1, *) class NS4 { } // expected-note {{class 'NS4' does not conform to the 'Sendable' protocol}} -// expected-complete-and-tns-note @-1 {{class 'NS4' does not conform to the 'Sendable' protocol}} +// expected-tns-note @-1 {{class 'NS4' does not conform to the 'Sendable' protocol}} @available(SwiftStdlib 5.1, *) func acceptCV(_: T) { } @@ -44,15 +46,15 @@ func testCV( acceptCV(ns1array) // expected-warning {{conformance of 'NS1' to 'Sendable' is unavailable}} - acceptCV(ns2) // expected-complete-and-tns-warning {{type 'NS2' does not conform to the 'Sendable' protocol}} + acceptCV(ns2) // expected-tns-warning {{type 'NS2' does not conform to the 'Sendable' protocol}} acceptCV(ns3) // expected-warning {{conformance of 'NS3' to 'Sendable' is only available in macOS 11.0 or newer}} // expected-note @-1 {{add 'if #available' version check}} - acceptCV(ns4) // expected-complete-and-tns-warning {{type 'NS4' does not conform to the 'Sendable' protocol}} + acceptCV(ns4) // expected-tns-warning {{type 'NS4' does not conform to the 'Sendable' protocol}} - acceptCV(fn) // expected-complete-and-tns-warning {{type '() -> Void' does not conform to the 'Sendable' protocol}} - // expected-complete-and-tns-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} + acceptCV(fn) // expected-tns-warning {{type '() -> Void' does not conform to the 'Sendable' protocol}} + // expected-tns-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} acceptSendableFn(fn) // expected-warning{{passing non-Sendable parameter 'fn' to function expecting a '@Sendable' closure}} } @@ -93,8 +95,8 @@ public actor MyActor: MyProto { func g(ns1: NS1) async { await nonisolatedAsyncFunc1(ns1) - // expected-tns-warning @-1 {{sending 'ns1' risks causing data races}} - // expected-tns-note @-2 {{sending 'self'-isolated 'ns1' to nonisolated global function 'nonisolatedAsyncFunc1' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-tns-ni-warning @-1 {{sending 'ns1' risks causing data races}} + // expected-tns-ni-note @-2 {{sending 'self'-isolated 'ns1' to nonisolated global function 'nonisolatedAsyncFunc1' risks causing data races between nonisolated and 'self'-isolated uses}} _ = await nonisolatedAsyncFunc2() } } @@ -162,18 +164,18 @@ class Super { @MainActor func bar (x : () -> ()) async {} - // expected-note@-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} + // expected-targeted-and-ni-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} @MainActor func foo2(x: T) async {} @MainActor func bar2(x: T) async {} - // expected-note@-1 {{consider making generic parameter 'T' conform to the 'Sendable' protocol}} {{14-14=: Sendable}} + // expected-targeted-and-ni-note @-1 {{consider making generic parameter 'T' conform to the 'Sendable' protocol}} {{14-14=: Sendable}} @MainActor func bar3(x: T) async {} - // expected-note@-1 {{consider making generic parameter 'T' conform to the 'Sendable' protocol}} {{25-25= & Sendable}} + // expected-targeted-and-ni-note @-1 {{consider making generic parameter 'T' conform to the 'Sendable' protocol}} {{25-25= & Sendable}} } // Make sure isolation crossing overrides check sendability @@ -182,16 +184,25 @@ class Super { class Sub : Super { override nonisolated func foo(x : () -> ()) async {} + // We do not emit an error for the override with + // NonisolatedNonsendingByDefault since the vtable thunk passes in MainActor + // so we are still in the main actor even though we are nonisolated. In the + // case of that being disabled, we cannot do this since we will hop off the + // actor. override nonisolated func bar(x : () -> ()) async {} - // expected-warning@-1 {{non-Sendable parameter type '() -> ()' cannot be sent from caller of superclass instance method 'bar(x:)' into nonisolated override}} + // expected-targeted-and-ni-warning@-1 {{non-Sendable parameter type '() -> ()' cannot be sent from caller of superclass instance method 'bar(x:)' into nonisolated override}} override nonisolated func foo2(x: T) async {} + // See comment above about why nonisolated overrides of superclass are allowed + // when is enabled NonisolatedNonsendingByDefault. override nonisolated func bar2(x: T) async {} - // expected-warning@-1 {{non-Sendable parameter type 'T' cannot be sent from caller of superclass instance method 'bar2(x:)' into nonisolated override}} + // expected-targeted-and-ni-warning @-1 {{non-Sendable parameter type 'T' cannot be sent from caller of superclass instance method 'bar2(x:)' into nonisolated override}} + // See comment above about why nonisolated overrides of superclass are allowed + // when is enabled NonisolatedNonsendingByDefault. override nonisolated func bar3(x: T) async {} - // expected-warning@-1 {{non-Sendable parameter type 'T' cannot be sent from caller of superclass instance method 'bar3(x:)' into nonisolated override}} + // expected-targeted-and-ni-warning @-1 {{non-Sendable parameter type 'T' cannot be sent from caller of superclass instance method 'bar3(x:)' into nonisolated override}} } @available(SwiftStdlib 5.1, *) @@ -217,7 +228,8 @@ class SubWSafeSubscript : SuperWSafeSubscript { class SuperWUnsafeSubscript { @MainActor subscript(x : T) -> Int { - // expected-note@-1 2{{consider making generic parameter 'T' conform to the 'Sendable' protocol}} + // expected-targeted-and-ni-note @-1 {{consider making generic parameter 'T' conform to the 'Sendable' protocol}} + // expected-targeted-and-ni-note @-2 {{consider making generic parameter 'T' conform to the 'Sendable' protocol}} get async { return 0 } @@ -226,10 +238,15 @@ class SuperWUnsafeSubscript { @available(SwiftStdlib 5.1, *) class SubWUnsafeSubscript : SuperWUnsafeSubscript { + // We do not emit an error for the override with + // NonisolatedNonsendingByDefault since the vtable thunk passes in MainActor + // so we are still in the main actor even though we are nonisolated. In the + // case of that being disabled, we cannot do this since we will hop off the + // actor. override nonisolated subscript(x : T) -> Int { get async { - // expected-warning@-2{{non-Sendable parameter type 'T' cannot be sent from caller of superclass subscript 'subscript(_:)' into nonisolated override}} - // expected-warning@-2{{non-Sendable parameter type 'T' cannot be sent from caller of superclass getter for subscript 'subscript(_:)' into nonisolated override}} + // expected-targeted-and-ni-warning@-2{{non-Sendable parameter type 'T' cannot be sent from caller of superclass subscript 'subscript(_:)' into nonisolated override}} + // expected-targeted-and-ni-warning@-2{{non-Sendable parameter type 'T' cannot be sent from caller of superclass getter for subscript 'subscript(_:)' into nonisolated override}} // there really shouldn't be two warnings produced here, see rdar://110846040 (Sendable diagnostics reported twice for subscript getters) return 0 } @@ -263,7 +280,7 @@ struct CustomActor { final class NonSendable { // expected-note @-1 5 {{class 'NonSendable' does not conform to the 'Sendable' protocol}} // TransferNonSendable emits 3 fewer errors here. - // expected-complete-and-tns-note @-3 {{class 'NonSendable' does not conform to the 'Sendable' protocol}} + // expected-tns-note @-3 {{class 'NonSendable' does not conform to the 'Sendable' protocol}} var value = "" @MainActor @@ -341,6 +358,7 @@ func testNonSendableBaseArg3() async { @Sendable func globalSendable(_ ns: NonSendable) async {} +#if !NONISOLATEDNONSENDING @available(SwiftStdlib 5.1, *) @MainActor func callNonisolatedAsyncClosure( @@ -348,14 +366,15 @@ func callNonisolatedAsyncClosure( g: (NonSendable) async -> Void ) async { await g(ns) - // expected-tns-warning @-1 {{sending 'ns' risks causing data races}} - // expected-tns-note @-2 {{sending main actor-isolated 'ns' to nonisolated callee risks causing data races between nonisolated and main actor-isolated uses}} + // expected-tns-ni-warning @-1 {{sending 'ns' risks causing data races}} + // expected-tns-ni-note @-2 {{sending main actor-isolated 'ns' to nonisolated callee risks causing data races between nonisolated and main actor-isolated uses}} let f: (NonSendable) async -> () = globalSendable // okay await f(ns) - // expected-tns-warning @-1 {{sending 'ns' risks causing data races}} - // expected-tns-note @-2 {{sending main actor-isolated 'ns' to nonisolated callee risks causing data races between nonisolated and main actor-isolated uses}} + // expected-tns-ni-warning @-1 {{sending 'ns' risks causing data races}} + // expected-tns-ni-note @-2 {{sending main actor-isolated 'ns' to nonisolated callee risks causing data races between nonisolated and main actor-isolated uses}} } +#endif @available(SwiftStdlib 5.1, *) func testLocalCaptures() { @@ -364,7 +383,7 @@ func testLocalCaptures() { @Sendable func a2() -> NonSendable { return ns - // expected-complete-and-tns-warning @-1 {{capture of 'ns' with non-Sendable type 'NonSendable' in a '@Sendable' local function}} + // expected-tns-warning @-1 {{capture of 'ns' with non-Sendable type 'NonSendable' in a '@Sendable' local function}} } } diff --git a/test/Concurrency/transfernonsendable.swift b/test/Concurrency/transfernonsendable.swift index ae26109da4a91..980677aecc880 100644 --- a/test/Concurrency/transfernonsendable.swift +++ b/test/Concurrency/transfernonsendable.swift @@ -1,4 +1,5 @@ -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -disable-availability-checking -verify -verify-additional-prefix tns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -disable-availability-checking -verify -verify-additional-prefix tns-ni- -verify-additional-prefix tns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -disable-availability-checking -verify -verify-additional-prefix tns-ni-ns- -verify-additional-prefix tns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // This run validates that for specific test cases around closures, we properly // emit errors in the type checker before we run sns. This ensures that we know that @@ -8,6 +9,7 @@ // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // @@ -106,15 +108,15 @@ enum MyEnum { extension MyActor { func warningIfCallingGetter() async { await self.klass.asyncCall() // expected-complete-warning {{passing argument of non-Sendable type 'NonSendableKlass' outside of actor-isolated context may introduce data races}} - // expected-tns-warning @-1 {{sending 'self.klass' risks causing data races}} - // expected-tns-note @-2 {{sending 'self'-isolated 'self.klass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-tns-ni-warning @-1 {{sending 'self.klass' risks causing data races}} + // expected-tns-ni-note @-2 {{sending 'self'-isolated 'self.klass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}} } func warningIfCallingAsyncOnFinalField() async { // Since we are calling finalKlass directly, we emit a warning here. await self.finalKlass.asyncCall() // expected-complete-warning {{passing argument of non-Sendable type 'NonSendableKlass' outside of actor-isolated context may introduce data races}} - // expected-tns-warning @-1 {{sending 'self.finalKlass' risks causing data races}} - // expected-tns-note @-2 {{sending 'self'-isolated 'self.finalKlass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-tns-ni-warning @-1 {{sending 'self.finalKlass' risks causing data races}} + // expected-tns-ni-note @-2 {{sending 'self'-isolated 'self.finalKlass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}} } // We do not warn on this since we warn in the caller of our getter instead. @@ -127,8 +129,8 @@ extension FinalActor { func warningIfCallingAsyncOnFinalField() async { // Since our whole class is final, we emit the error directly here. await self.klass.asyncCall() // expected-complete-warning {{passing argument of non-Sendable type 'NonSendableKlass' outside of actor-isolated context may introduce data races}} - // expected-tns-warning @-1 {{sending 'self.klass' risks causing data races}} - // expected-tns-note @-2 {{sending 'self'-isolated 'self.klass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-tns-ni-warning @-1 {{sending 'self.klass' risks causing data races}} + // expected-tns-ni-note @-2 {{sending 'self'-isolated 'self.klass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}} } } @@ -1572,8 +1574,12 @@ func functionArgumentIntoClosure(_ x: @escaping () -> ()) async { let a = MainActorIsolatedKlass() var c = NonSendableKlass() for _ in 0..<1024 { - await useValueAsync(c) // expected-tns-warning {{sending 'c' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'c' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + // This works with nonisolated(nonsending) since the first time through the + // loop we are disconnected... meaning that we are ok. The second time + // through the loop, we are now main actor isolated, but again b/c we + // inherit isolation, we are ok. + await useValueAsync(c) // expected-tns-ni-warning {{sending 'c' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'c' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' outside of main actor-isolated context may introduce data races}} c = a.klass } @@ -1583,8 +1589,8 @@ func functionArgumentIntoClosure(_ x: @escaping () -> ()) async { let a = MainActorIsolatedKlass() var c = NonSendableKlass() for _ in 0..<1024 { - await useValueAsync(c) // expected-tns-warning {{sending 'c' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'c' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(c) // expected-tns-ni-warning {{sending 'c' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'c' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' outside of main actor-isolated context may introduce data races}} c = a.klassLet } @@ -1832,8 +1838,8 @@ actor FunctionWithSendableResultAndIsolationActor { @MainActor func previouslyBrokenTestCase(ns: NonSendableKlass) async -> SendableGenericStruct? { return await { () -> SendableGenericStruct? in - return await ns.getSendableGenericStructAsync() // expected-tns-warning {{sending 'ns' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'ns' to nonisolated instance method 'getSendableGenericStructAsync()' risks causing data races between nonisolated and main actor-isolated uses}} + return await ns.getSendableGenericStructAsync() // expected-tns-ni-warning {{sending 'ns' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'ns' to nonisolated instance method 'getSendableGenericStructAsync()' risks causing data races between nonisolated and main actor-isolated uses}} }() } diff --git a/test/Concurrency/transfernonsendable_asynclet.swift b/test/Concurrency/transfernonsendable_asynclet.swift index 1408f828d39b9..8db02034ef315 100644 --- a/test/Concurrency/transfernonsendable_asynclet.swift +++ b/test/Concurrency/transfernonsendable_asynclet.swift @@ -1,7 +1,9 @@ // RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // diff --git a/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift b/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift index 0c52bb1d73cbd..95e0937110421 100644 --- a/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift +++ b/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift @@ -1,8 +1,11 @@ // RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -o - | %FileCheck %s -// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null -verify-additional-prefix ni- +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -o - -enable-upcoming-feature NonisolatedNonsendingByDefault | %FileCheck %s +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null -enable-upcoming-feature NonisolatedNonsendingByDefault -verify-additional-prefix ni-ns- // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // This test validates the behavior of transfernonsendable around // closure literals @@ -204,8 +207,8 @@ func test_CallerAsyncNormal_CalleeSyncNonIsolated() async { // CHECK-LABEL: closure #1 in test_CallerAsyncNormal_CalleeSyncNonIsolated() // CHECK-NEXT: Isolation: global_actor. type: CustomActor - await asyncNormalAcceptsClosure { } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{sending global actor 'CustomActor'-isolated value of non-Sendable type '() -> ()' to nonisolated global function 'asyncNormalAcceptsClosure' risks causing races in between global actor 'CustomActor'-isolated and nonisolated uses}} + await asyncNormalAcceptsClosure { } // expected-ni-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} + // expected-ni-note @-1 {{sending global actor 'CustomActor'-isolated value of non-Sendable type '() -> ()' to nonisolated global function 'asyncNormalAcceptsClosure' risks causing races in between global actor 'CustomActor'-isolated and nonisolated uses}} // CHECK-LABEL: closure #2 in test_CallerAsyncNormal_CalleeSyncNonIsolated() // CHECK-NEXT: Isolation: nonisolated @@ -244,8 +247,8 @@ func test_CallerAsyncNormal_CalleeAsyncNonIsolated() async { // CHECK-LABEL: closure #1 in test_CallerAsyncNormal_CalleeAsyncNonIsolated() // CHECK-NEXT: Isolation: global_actor. type: CustomActor - await asyncNormalAcceptsAsyncClosure { } // expected-error {{sending value of non-Sendable type '() async -> ()' risks causing data races}} - // expected-note @-1 {{sending global actor 'CustomActor'-isolated value of non-Sendable type '() async -> ()' to nonisolated global function 'asyncNormalAcceptsAsyncClosure' risks causing races in between global actor 'CustomActor'-isolated and nonisolated uses}} + await asyncNormalAcceptsAsyncClosure { } // expected-ni-error {{sending value of non-Sendable type '() async -> ()' risks causing data races}} + // expected-ni-note @-1 {{sending global actor 'CustomActor'-isolated value of non-Sendable type '() async -> ()' to nonisolated global function 'asyncNormalAcceptsAsyncClosure' risks causing races in between global actor 'CustomActor'-isolated and nonisolated uses}} // CHECK-LABEL: closure #2 in test_CallerAsyncNormal_CalleeAsyncNonIsolated() // CHECK-NEXT: Isolation: nonisolated @@ -432,8 +435,8 @@ extension MyActor { // CHECK-LABEL: closure #1 in MyActor.test_CallerAsyncNormal_CalleeSyncNonIsolated() // CHECK-NEXT: Isolation: actor_instance. name: 'self' - await asyncNormalAcceptsClosure { print(self) } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{sending 'self'-isolated value of non-Sendable type '() -> ()' to nonisolated global function 'asyncNormalAcceptsClosure' risks causing races in between 'self'-isolated and nonisolated uses}} + await asyncNormalAcceptsClosure { print(self) } // expected-ni-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} + // expected-ni-note @-1 {{sending 'self'-isolated value of non-Sendable type '() -> ()' to nonisolated global function 'asyncNormalAcceptsClosure' risks causing races in between 'self'-isolated and nonisolated uses}} // CHECK-LABEL: closure #2 in MyActor.test_CallerAsyncNormal_CalleeSyncNonIsolated() // CHECK-NEXT: Isolation: nonisolated @@ -473,8 +476,8 @@ extension MyActor { // CHECK-LABEL: closure #1 in MyActor.test_CallerAsyncNormal_CalleeAsyncNonIsolated() // CHECK-NEXT: Isolation: actor_instance. name: 'self' - await asyncNormalAcceptsAsyncClosure { print(self) } // expected-error {{sending value of non-Sendable type '() async -> ()' risks causing data races}} - // expected-note @-1 {{sending 'self'-isolated value of non-Sendable type '() async -> ()' to nonisolated global function 'asyncNormalAcceptsAsyncClosure' risks causing races in between 'self'-isolated and nonisolated uses}} + await asyncNormalAcceptsAsyncClosure { print(self) } // expected-ni-error {{sending value of non-Sendable type '() async -> ()' risks causing data races}} + // expected-ni-note @-1 {{sending 'self'-isolated value of non-Sendable type '() async -> ()' to nonisolated global function 'asyncNormalAcceptsAsyncClosure' risks causing races in between 'self'-isolated and nonisolated uses}} // CHECK-LABEL: closure #2 in MyActor.test_CallerAsyncNormal_CalleeAsyncNonIsolated() // CHECK-NEXT: Isolation: nonisolated diff --git a/test/Concurrency/transfernonsendable_functionsubtyping.swift b/test/Concurrency/transfernonsendable_functionsubtyping.swift index de7b2fc8bb893..22739fcc20053 100644 --- a/test/Concurrency/transfernonsendable_functionsubtyping.swift +++ b/test/Concurrency/transfernonsendable_functionsubtyping.swift @@ -1,4 +1,5 @@ // RUN: %target-typecheck-verify-swift -swift-version 6 +// RUN: %target-typecheck-verify-swift -swift-version 6 -enable-upcoming-feature NonisolatedNonsendingByDefault // READ THIS! This file only contains tests that validate that the relevant // function subtyping rules for sending work. Please do not put other tests in @@ -6,6 +7,7 @@ // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // diff --git a/test/Concurrency/transfernonsendable_global_actor.swift b/test/Concurrency/transfernonsendable_global_actor.swift index fa440e65ec268..b991837f2fd01 100644 --- a/test/Concurrency/transfernonsendable_global_actor.swift +++ b/test/Concurrency/transfernonsendable_global_actor.swift @@ -1,7 +1,9 @@ -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix tns- %s -o /dev/null -parse-as-library -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix tns-ni- -verify-additional-prefix tns- %s -o /dev/null -parse-as-library -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix tns-ni-ns- -verify-additional-prefix tns- %s -o /dev/null -parse-as-library -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // @@ -150,8 +152,8 @@ private struct StructContainingValue { // expected-complete-note 2{{}} var x = StructContainingValue() x.x = firstList - await transferToNonIsolated(x) // expected-tns-warning {{sending 'x' risks causing data races}} - // expected-tns-note @-1 {{sending global actor 'CustomActor'-isolated 'x' to nonisolated global function 'transferToNonIsolated' risks causing data races between nonisolated and global actor 'CustomActor'-isolated uses}} + await transferToNonIsolated(x) // expected-tns-ni-warning {{sending 'x' risks causing data races}} + // expected-tns-ni-note @-1 {{sending global actor 'CustomActor'-isolated 'x' to nonisolated global function 'transferToNonIsolated' risks causing data races between nonisolated and global actor 'CustomActor'-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructContainingValue' outside of global actor 'CustomActor'-isolated context may introduce data races}} useValue(x) @@ -174,8 +176,8 @@ private struct StructContainingValue { // expected-complete-note 2{{}} x.1 = firstList - await transferToNonIsolated(x) // expected-tns-warning {{sending 'x' risks causing data races}} - // expected-tns-note @-1 {{sending global actor 'CustomActor'-isolated 'x' to nonisolated global function 'transferToNonIsolated' risks causing data races between nonisolated and global actor 'CustomActor'-isolated uses}} + await transferToNonIsolated(x) // expected-tns-ni-warning {{sending 'x' risks causing data races}} + // expected-tns-ni-note @-1 {{sending global actor 'CustomActor'-isolated 'x' to nonisolated global function 'transferToNonIsolated' risks causing data races between nonisolated and global actor 'CustomActor'-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type '(NonSendableLinkedList, NonSendableLinkedList)' outside of global actor 'CustomActor'-isolated context may introduce data races}} // expected-complete-warning @-3 {{passing argument of non-Sendable type '(NonSendableLinkedList, NonSendableLinkedList)' outside of global actor 'CustomActor'-isolated context may introduce data races}} @@ -195,8 +197,8 @@ struct Clock { // We used to crash when inferring the type for the diagnostic below. @MainActor func testIndirectParametersHandledCorrectly() async { let c = Clock() - let _: Int = await c.measure { // expected-tns-warning {{sending value of non-Sendable type '() async -> Int' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated value of non-Sendable type '() async -> Int' to nonisolated instance method 'measure' risks causing races in between main actor-isolated and nonisolated uses}} + let _: Int = await c.measure { // expected-tns-ni-warning {{sending value of non-Sendable type '() async -> Int' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated value of non-Sendable type '() async -> Int' to nonisolated instance method 'measure' risks causing races in between main actor-isolated and nonisolated uses}} try! await c.sleep() } } @@ -255,8 +257,8 @@ struct Clock { let erased: () -> Void = closure - await useValueAsync(erased) // expected-tns-warning {{sending 'erased' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-tns-ni-warning {{sending 'erased' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type '() -> Void' outside of main actor-isolated context may introduce data races}} // expected-complete-note @-3 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} } @@ -264,8 +266,8 @@ struct Clock { @MainActor func synchronousActorIsolatedFunctionError() async { let erased: () -> Void = mainActorFunction - await useValueAsync(erased) // expected-tns-warning {{sending 'erased' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-tns-ni-warning {{sending 'erased' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type '() -> Void' outside of main actor-isolated context may introduce data races}} // expected-complete-note @-3 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} } @@ -273,8 +275,8 @@ struct Clock { @MainActor func synchronousActorIsolatedGenericFunctionError(_ t: T) async { let erased: (T) -> Void = useValueMainActor - await useValueAsync(erased) // expected-tns-warning {{sending 'erased' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-tns-ni-warning {{sending 'erased' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type '(T) -> Void' outside of main actor-isolated context may introduce data races}} // expected-complete-note @-3 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} } @@ -287,8 +289,8 @@ struct Clock { let t = Test() let erased: () -> Void = t.foo - await useValueAsync(erased) // expected-tns-warning {{sending 'erased' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-tns-ni-warning {{sending 'erased' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type '() -> Void' outside of main actor-isolated context may introduce data races}} // expected-complete-note @-3 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} } @@ -301,8 +303,8 @@ struct Clock { let t = Test() let erased: () -> Void = t.foo - await useValueAsync(erased) // expected-tns-warning {{sending 'erased' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-tns-ni-warning {{sending 'erased' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type '() -> Void' outside of main actor-isolated context may introduce data races}} // expected-complete-note @-3 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} } diff --git a/test/Concurrency/transfernonsendable_global_actor_nonsendable.swift b/test/Concurrency/transfernonsendable_global_actor_nonsendable.swift index f4fe9669ef6af..b6553a9cc6807 100644 --- a/test/Concurrency/transfernonsendable_global_actor_nonsendable.swift +++ b/test/Concurrency/transfernonsendable_global_actor_nonsendable.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -parse-as-library +// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -parse-as-library -enable-upcoming-feature NonisolatedNonsendingByDefault // READ THIS: This test is testing specifically behavior around global actor // isolated types that are nonsendable. This is a bit of a corner case so we use @@ -6,6 +7,7 @@ // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // diff --git a/test/Concurrency/transfernonsendable_global_actor_sending.swift b/test/Concurrency/transfernonsendable_global_actor_sending.swift index a0fe45df8881c..f4d0c9fbec375 100644 --- a/test/Concurrency/transfernonsendable_global_actor_sending.swift +++ b/test/Concurrency/transfernonsendable_global_actor_sending.swift @@ -1,9 +1,13 @@ // RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -parse-as-library +// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -parse-as-library -enable-upcoming-feature NonisolatedNonsendingByDefault + // README: Once we loosen the parser so that sending is rejected in Sema // instead of the parser, move into the normal // transfernonsendable_global_actor.swift +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault + //////////////////////// // MARK: Declarations // //////////////////////// diff --git a/test/Concurrency/transfernonsendable_global_actor_swift6.swift b/test/Concurrency/transfernonsendable_global_actor_swift6.swift index a8bf80094f830..9c18e13977c77 100644 --- a/test/Concurrency/transfernonsendable_global_actor_swift6.swift +++ b/test/Concurrency/transfernonsendable_global_actor_swift6.swift @@ -1,4 +1,5 @@ -// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -parse-as-library +// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix ni- %s -o /dev/null -parse-as-library +// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix ni-ns- %s -o /dev/null -parse-as-library -enable-upcoming-feature NonisolatedNonsendingByDefault // README: This is testing specific patterns around global actors that are // slightly different in between swift 5 and swift 6. The normal global actor @@ -6,6 +7,7 @@ // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // @@ -44,22 +46,22 @@ var booleanFlag: Bool { false } let erased: () -> Void = closure - await useValueAsync(erased) // expected-error {{sending 'erased' risks causing data races}} - // expected-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-ni-error {{sending 'erased' risks causing data races}} + // expected-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} } @MainActor func synchronousActorIsolatedFunctionError() async { let erased: () -> Void = mainActorFunction - await useValueAsync(erased) // expected-error {{sending 'erased' risks causing data races}} - // expected-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-ni-error {{sending 'erased' risks causing data races}} + // expected-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} } @MainActor func synchronousActorIsolatedGenericFunctionError(_ t: T) async { let erased: (T) -> Void = useValueMainActor - await useValueAsync(erased) // expected-error {{sending 'erased' risks causing data races}} - // expected-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-ni-error {{sending 'erased' risks causing data races}} + // expected-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} } @MainActor func synchronousActorIsolatedClassMethodError() async { @@ -70,8 +72,8 @@ var booleanFlag: Bool { false } let t = Test() let erased: () -> Void = t.foo - await useValueAsync(erased) // expected-error {{sending 'erased' risks causing data races}} - // expected-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-ni-error {{sending 'erased' risks causing data races}} + // expected-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} } @MainActor func synchronousActorIsolatedFinalClassMethodError() async { @@ -82,6 +84,6 @@ var booleanFlag: Bool { false } let t = Test() let erased: () -> Void = t.foo - await useValueAsync(erased) // expected-error {{sending 'erased' risks causing data races}} - // expected-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-ni-error {{sending 'erased' risks causing data races}} + // expected-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} } diff --git a/test/Concurrency/transfernonsendable_initializers.swift b/test/Concurrency/transfernonsendable_initializers.swift index 4eb41f9ec759d..ceef4f8745ab7 100644 --- a/test/Concurrency/transfernonsendable_initializers.swift +++ b/test/Concurrency/transfernonsendable_initializers.swift @@ -1,7 +1,9 @@ // RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // This test validates the behavior of transfernonsendable around initializers. diff --git a/test/Concurrency/transfernonsendable_isolationcrossing_partialapply.swift b/test/Concurrency/transfernonsendable_isolationcrossing_partialapply.swift index c24a94e778149..0a293980726a1 100644 --- a/test/Concurrency/transfernonsendable_isolationcrossing_partialapply.swift +++ b/test/Concurrency/transfernonsendable_isolationcrossing_partialapply.swift @@ -1,7 +1,9 @@ // RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -disable-availability-checking -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -disable-availability-checking -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // This test validates how we handle partial applies that are isolated to a // specific isolation domain (causing isolation crossings to occur). diff --git a/test/Concurrency/transfernonsendable_nonisolated.swift b/test/Concurrency/transfernonsendable_nonisolated.swift index 73aaf5b82225e..6e208f6a2bb54 100644 --- a/test/Concurrency/transfernonsendable_nonisolated.swift +++ b/test/Concurrency/transfernonsendable_nonisolated.swift @@ -1,7 +1,9 @@ // RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // This test validates behavior of transfernonsendable around nonisolated // functions and fields. diff --git a/test/Concurrency/transfernonsendable_nonisolatedunsafe.swift b/test/Concurrency/transfernonsendable_nonisolatedunsafe.swift index ab9fb1752b5a1..13f1c2e414442 100644 --- a/test/Concurrency/transfernonsendable_nonisolatedunsafe.swift +++ b/test/Concurrency/transfernonsendable_nonisolatedunsafe.swift @@ -1,10 +1,12 @@ // RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix tns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix tns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // READ THIS: This test is intended to centralize all tests that use // nonisolated(unsafe). // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // diff --git a/test/Concurrency/transfernonsendable_objc.swift b/test/Concurrency/transfernonsendable_objc.swift index b726878b9c7d0..56099d5097b84 100644 --- a/test/Concurrency/transfernonsendable_objc.swift +++ b/test/Concurrency/transfernonsendable_objc.swift @@ -1,8 +1,9 @@ -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -enable-upcoming-feature RegionBasedIsolation -target %target-swift-5.1-abi-triple %s -o /dev/null -import-objc-header %S/Inputs/transfernonsendable_objc.h -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple %s -o /dev/null -import-objc-header %S/Inputs/transfernonsendable_objc.h -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple %s -o /dev/null -import-objc-header %S/Inputs/transfernonsendable_objc.h -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: objc_interop // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability -// REQUIRES: swift_feature_RegionBasedIsolation +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault import Foundation diff --git a/test/Concurrency/transfernonsendable_ownership.swift b/test/Concurrency/transfernonsendable_ownership.swift index fe0fd7102e736..68bed57c74b37 100644 --- a/test/Concurrency/transfernonsendable_ownership.swift +++ b/test/Concurrency/transfernonsendable_ownership.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -enable-upcoming-feature GlobalActorIsolatedTypesUsability %s -o /dev/null +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -enable-upcoming-feature GlobalActorIsolatedTypesUsability %s -o /dev/null -enable-upcoming-feature NonisolatedNonsendingByDefault // This test validates the behavior of transfer non sendable around ownership // constructs like non copyable types, consuming/borrowing parameters, and inout @@ -6,6 +7,7 @@ // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // diff --git a/test/Concurrency/transfernonsendable_preconcurrency.swift b/test/Concurrency/transfernonsendable_preconcurrency.swift index 08f87c3fa89cf..7577948bf8c27 100644 --- a/test/Concurrency/transfernonsendable_preconcurrency.swift +++ b/test/Concurrency/transfernonsendable_preconcurrency.swift @@ -11,9 +11,11 @@ // Test swift 6 // RUN: %target-swift-frontend -swift-version 6 %s -emit-sil -o /dev/null -verify -verify-additional-prefix swift-6- -parse-as-library -I %t -target %target-swift-5.1-abi-triple +// RUN: %target-swift-frontend -swift-version 6 %s -emit-sil -o /dev/null -verify -verify-additional-prefix swift-6- -parse-as-library -I %t -target %target-swift-5.1-abi-triple -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // README: This test is meant to test the interaction of transfernonsendable and // preconcurrency. Please only keep such tests in this file. diff --git a/test/Concurrency/transfernonsendable_preconcurrency_sending.swift b/test/Concurrency/transfernonsendable_preconcurrency_sending.swift index dd2d68a356723..a46ee44de1dc2 100644 --- a/test/Concurrency/transfernonsendable_preconcurrency_sending.swift +++ b/test/Concurrency/transfernonsendable_preconcurrency_sending.swift @@ -11,9 +11,11 @@ // Test swift 6 // RUN: %target-swift-frontend -swift-version 6 %s -emit-sil -o /dev/null -verify -verify-additional-prefix swift-6- -parse-as-library -I %t -target %target-swift-5.1-abi-triple +// RUN: %target-swift-frontend -swift-version 6 %s -emit-sil -o /dev/null -verify -verify-additional-prefix swift-6- -parse-as-library -I %t -target %target-swift-5.1-abi-triple -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // README: This test is meant to test the interaction of transfernonsendable, // preconcurrency, and transferring. Please only keep such tests in this file. diff --git a/test/Concurrency/transfernonsendable_rbi_result.swift b/test/Concurrency/transfernonsendable_rbi_result.swift index ea730c83b2d92..fc86d0ca4519d 100644 --- a/test/Concurrency/transfernonsendable_rbi_result.swift +++ b/test/Concurrency/transfernonsendable_rbi_result.swift @@ -1,7 +1,9 @@ -// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -swift-version 6 -parse-as-library %s -emit-sil -o /dev/null -verify +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -swift-version 6 -disable-availability-checking -parse-as-library %s -emit-sil -o /dev/null -verify -verify-additional-prefix ni- +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -swift-version 6 -disable-availability-checking -parse-as-library %s -emit-sil -o /dev/null -verify -verify-additional-prefix ni-ns- -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: asserts // REQUIRES: concurrency +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault /////////////////////// // MARK: Declaration // @@ -20,9 +22,13 @@ struct CustomActor { class NonSendable {} // expected-note 3{{}} func passNonSendable(_: NonSendable) async { } +func passTwoNonSendable(_: NonSendable, _: NonSendable) async { } func returnsNonSendable() async -> NonSendable { NonSendable() } +@MainActor +func sendToMain(_ t: T) async {} + @MainActor func mainActorPassNonSendable(_: NonSendable) async { } @@ -93,9 +99,22 @@ actor A { func callNonisolatedFuncsFromActor(ns: NonSendable) async { // Non-sendable value passed from nonisolated to actor isolated + // We do not error in ni-ns since we just merge pass non sendable. await passNonSendable(ns) - // expected-error @-1 {{sending 'ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'ns' to nonisolated global function 'passNonSendable' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-ni-error @-1 {{sending 'ns' risks causing data races}} + // expected-ni-note @-2 {{sending 'self'-isolated 'ns' to nonisolated global function 'passNonSendable' risks causing data races between nonisolated and 'self'-isolated uses}} + + // We error here in both modes but in different places. In NI mode, we error + // on passing ns to a nonisolated function. With ni-ns, we do not error + // there since we inherit isolation from the caller. + // + // In contrast, when ni-ns is enabled, we error on sendToMain since we merge + // ns2 into ns's region causing it to be self-isolated. + let ns2 = NonSendable() + await passTwoNonSendable(ns, ns2) // expected-ni-error {{sending 'ns' risks causing data races}} + // expected-ni-note @-1 {{sending 'self'-isolated 'ns' to nonisolated global function 'passTwoNonSendable' risks causing data races between nonisolated and 'self'-isolated uses}} + await sendToMain(ns2) // expected-ni-ns-error {{sending 'ns2' risks causing data races}} + // expected-ni-ns-note @-1 {{sending 'self'-isolated 'ns2' to main actor-isolated global function 'sendToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}} _ = await returnsNonSendable() } diff --git a/test/Concurrency/transfernonsendable_region_based_sendability.swift b/test/Concurrency/transfernonsendable_region_based_sendability.swift index 30932af4c7dbb..1c39c643de782 100644 --- a/test/Concurrency/transfernonsendable_region_based_sendability.swift +++ b/test/Concurrency/transfernonsendable_region_based_sendability.swift @@ -1,7 +1,9 @@ // RUN: %target-swift-frontend -strict-concurrency=complete -target %target-swift-5.1-abi-triple -parse-as-library -emit-sil -o /dev/null -verify -verify-additional-prefix tns- %s -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -strict-concurrency=complete -target %target-swift-5.1-abi-triple -parse-as-library -emit-sil -o /dev/null -verify -verify-additional-prefix tns- %s -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault /* This file tests the early features of the flow-sensitive Sendable checking implemented by the TransferNonSendable SIL pass. diff --git a/test/Concurrency/transfernonsendable_sending_params.swift b/test/Concurrency/transfernonsendable_sending_params.swift index e71857f4f2a87..55a06267503d2 100644 --- a/test/Concurrency/transfernonsendable_sending_params.swift +++ b/test/Concurrency/transfernonsendable_sending_params.swift @@ -1,7 +1,9 @@ -// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -strict-concurrency=complete -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -strict-concurrency=complete -verify -verify-additional-prefix ni- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -strict-concurrency=complete -verify -verify-additional-prefix ni-ns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // diff --git a/test/Concurrency/transfernonsendable_sending_results.swift b/test/Concurrency/transfernonsendable_sending_results.swift index a3615b29546fe..1921886ab5937 100644 --- a/test/Concurrency/transfernonsendable_sending_results.swift +++ b/test/Concurrency/transfernonsendable_sending_results.swift @@ -1,7 +1,9 @@ // RUN: %target-swift-frontend -emit-sil -parse-as-library -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -parse-as-library -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // diff --git a/test/Concurrency/transfernonsendable_typed_errors.swift b/test/Concurrency/transfernonsendable_typed_errors.swift index cade1abcc2e03..f563ecfdd843a 100644 --- a/test/Concurrency/transfernonsendable_typed_errors.swift +++ b/test/Concurrency/transfernonsendable_typed_errors.swift @@ -1,7 +1,9 @@ // RUN: %target-swift-frontend -swift-version 6 -Xllvm -sil-regionbasedisolation-force-use-of-typed-errors -emit-sil -o /dev/null %s -verify -target %target-swift-5.1-abi-triple +// RUN: %target-swift-frontend -swift-version 6 -Xllvm -sil-regionbasedisolation-force-use-of-typed-errors -emit-sil -o /dev/null %s -verify -target %target-swift-5.1-abi-triple -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // READ THIS: This test is only intended to test typed errors that are fallback // error paths that are only invoked if we can't find a name for the value being diff --git a/test/Concurrency/transfernonsendable_unavailable_conformance.swift b/test/Concurrency/transfernonsendable_unavailable_conformance.swift index 883b1447b07fc..aac9d80b2bb87 100644 --- a/test/Concurrency/transfernonsendable_unavailable_conformance.swift +++ b/test/Concurrency/transfernonsendable_unavailable_conformance.swift @@ -1,8 +1,9 @@ -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -enable-upcoming-feature RegionBasedIsolation -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability -// REQUIRES: swift_feature_RegionBasedIsolation +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // This test makes sure that we treat types with an unavailable Sendable // conformance as being non-Sendable. diff --git a/test/Concurrency/transfernonsendable_warning_until_swift6.swift b/test/Concurrency/transfernonsendable_warning_until_swift6.swift index 9f194ee040248..3548524be7c9e 100644 --- a/test/Concurrency/transfernonsendable_warning_until_swift6.swift +++ b/test/Concurrency/transfernonsendable_warning_until_swift6.swift @@ -1,6 +1,8 @@ // RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -swift-version 6 +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -swift-version 6 -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // This test makes sure that all of our warnings are errors in swift6 mode. From f5d547cd443782ead95c5ba96c10512d0713e9b4 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 4 Apr 2025 06:09:27 +0100 Subject: [PATCH 03/10] AST: Cut down on `DescriptiveDeclKind` usage in `DiagnosticsSIL.def` (cherry picked from commit 5c190b961300202886cfa1970b8506344853f21f) --- include/swift/AST/DiagnosticsSIL.def | 43 ++++++------- .../Mandatory/DataflowDiagnostics.cpp | 11 ++-- lib/SILOptimizer/Mandatory/FlowIsolation.cpp | 6 +- .../Mandatory/SendNonSendable.cpp | 61 ++++++++----------- 4 files changed, 55 insertions(+), 66 deletions(-) diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 4e5e1633db597..7d4b6032dcded 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -315,12 +315,12 @@ ERROR(missing_never_call_closure,none, (Type)) ERROR(missing_return_decl,none, - "missing return in %1 expected to return %0", - (Type, DescriptiveDeclKind)) + "missing return in %kindonly1 expected to return %0", + (Type, const AbstractFunctionDecl *)) ERROR(missing_never_call_decl,none, - "%1 with uninhabited return type %0 is missing " + "%kindonly1 with uninhabited return type %0 is missing " "call to another never-returning function on all paths", - (Type, DescriptiveDeclKind)) + (Type, const AbstractFunctionDecl *)) NOTE(missing_return_last_expr_note,none, "did you mean to return the last expression?", ()) @@ -701,8 +701,9 @@ WARNING(warning_int_to_fp_inexact, none, // Flow-isolation diagnostics ERROR(isolated_after_nonisolated, none, - "cannot access %1 %2 here in %select{nonisolated initializer|deinitializer}0", - (bool, DescriptiveDeclKind, DeclName)) + "cannot access %kind1 here in " + "%select{nonisolated initializer|deinitializer}0", + (bool, const ValueDecl *)) NOTE(nonisolated_blame, none, "after %1%2 %3, " "only nonisolated properties of 'self' can be accessed from " "%select{this init|a deinit}0", (bool, StringRef, StringRef, DeclName)) @@ -984,16 +985,16 @@ NOTE(regionbasedisolation_type_use_after_send, none, "sending value of non-Sendable type %0 to %1 callee risks causing data races between %1 and local %2 uses", (Type, ActorIsolation, ActorIsolation)) NOTE(regionbasedisolation_type_use_after_send_callee, none, - "sending value of non-Sendable type %0 to %1 %2 %3 risks causing data " - "races between %1 and local %4 uses", - (Type, ActorIsolation, DescriptiveDeclKind, DeclName, ActorIsolation)) + "sending value of non-Sendable type %0 to %1 %kind2 risks causing data " + "races between %1 and local %3 uses", + (Type, ActorIsolation, const ValueDecl *, ActorIsolation)) NOTE(regionbasedisolation_named_info_send_yields_race, none, "sending %1%0 to %2 callee risks causing data races between %2 and local %3 uses", (Identifier, StringRef, ActorIsolation, ActorIsolation)) NOTE(regionbasedisolation_named_info_send_yields_race_callee, none, - "sending %1%0 to %2 %3 %4 risks causing data races between %2 and local %5 uses", - (Identifier, StringRef, ActorIsolation, DescriptiveDeclKind, DeclName, ActorIsolation)) + "sending %1%0 to %2 %kind3 risks causing data races between %2 and local %4 uses", + (Identifier, StringRef, ActorIsolation, const ValueDecl *, ActorIsolation)) // Use after send closure. NOTE(regionbasedisolation_type_isolated_capture_yields_race, none, @@ -1016,8 +1017,8 @@ NOTE(regionbasedisolation_typed_use_after_sending, none, "Passing value of non-Sendable type %0 as a 'sending' argument risks causing races in between local and caller code", (Type)) NOTE(regionbasedisolation_typed_use_after_sending_callee, none, - "Passing value of non-Sendable type %0 as a 'sending' argument to %1 %2 risks causing races in between local and caller code", - (Type, DescriptiveDeclKind, DeclName)) + "Passing value of non-Sendable type %0 as a 'sending' argument to %kind1 risks causing races in between local and caller code", + (Type, const ValueDecl *)) //=== // Sending Never Sendable Emitter @@ -1026,8 +1027,8 @@ NOTE(regionbasedisolation_named_send_never_sendable, none, "sending %1%0 to %2 callee risks causing data races between %2 and %3 uses", (Identifier, StringRef, ActorIsolation, StringRef)) NOTE(regionbasedisolation_named_send_never_sendable_callee, none, - "sending %1%0 to %2 %3 %4 risks causing data races between %2 and %5 uses", - (Identifier, StringRef, ActorIsolation, DescriptiveDeclKind, DeclName, StringRef)) + "sending %1%0 to %2 %kind3 risks causing data races between %2 and %4 uses", + (Identifier, StringRef, ActorIsolation, const ValueDecl *, StringRef)) NOTE(regionbasedisolation_named_send_into_sending_param, none, "%0%1 is passed as a 'sending' parameter; Uses in callee may race with " @@ -1051,8 +1052,8 @@ NOTE(regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value_ "closure captures %0 which is accessible to code in the current task", (DeclName)) NOTE(regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_boxed_value_task_isolated, none, - "closure captures reference to mutable %1 %0 which is accessible to code in the current task", - (DeclName, DescriptiveDeclKind)) + "closure captures reference to mutable %kind0 which is accessible to code in the current task", + (const ValueDecl *)) NOTE(regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value_region, none, "closure captures %1 which is accessible to %0 code", (StringRef, DeclName)) @@ -1068,8 +1069,8 @@ NOTE(regionbasedisolation_closure_captures_actor, none, (DeclName, StringRef)) NOTE(regionbasedisolation_typed_tns_passed_to_sending_callee, none, - "Passing %0 value of non-Sendable type %1 as a 'sending' parameter to %2 %3 risks causing races inbetween %0 uses and uses reachable from %3", - (StringRef, Type, DescriptiveDeclKind, DeclName)) + "Passing %0 value of non-Sendable type %1 as a 'sending' parameter to %kind2 risks causing races inbetween %0 uses and uses reachable from %2", + (StringRef, Type, const ValueDecl *)) NOTE(regionbasedisolation_named_send_nt_asynclet_capture, none, "sending %1 %0 into async let risks causing data races between nonisolated and %1 uses", @@ -1078,8 +1079,8 @@ NOTE(regionbasedisolation_typed_sendneversendable_via_arg, none, "sending %0 value of non-Sendable type %1 to %2 callee risks causing races in between %0 and %2 uses", (StringRef, Type, ActorIsolation)) NOTE(regionbasedisolation_typed_sendneversendable_via_arg_callee, none, - "sending %0 value of non-Sendable type %1 to %2 %3 %4 risks causing races in between %0 and %2 uses", - (StringRef, Type, ActorIsolation, DescriptiveDeclKind, DeclName)) + "sending %0 value of non-Sendable type %1 to %2 %kind3 risks causing races in between %0 and %2 uses", + (StringRef, Type, ActorIsolation, const ValueDecl *)) NOTE(regionbasedisolation_isolated_conformance_introduced, none, "isolated conformance to %kind0 can be introduced here", diff --git a/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp b/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp index 5e161eb690350..ea8397a6fd295 100644 --- a/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp +++ b/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp @@ -69,10 +69,9 @@ static void diagnoseMissingReturn(const UnreachableInst *UI, Context.Diags.diagnose(expr->getStartLoc(), diag::missing_return_closure, ResTy); } else { - auto *DC = FLoc.getAsDeclContext(); - assert(DC && DC->getAsDecl() && "not a declaration?"); + auto *FD = FLoc.castToASTNode(); Context.Diags.diagnose(expr->getStartLoc(), diag::missing_return_decl, - ResTy, DC->getAsDecl()->getDescriptiveKind()); + ResTy, FD); } Context.Diags .diagnose(expr->getStartLoc(), diag::missing_return_last_expr_note) @@ -89,12 +88,10 @@ static void diagnoseMissingReturn(const UnreachableInst *UI, : diag::missing_return_closure; diagnose(Context, L.getEndSourceLoc(), diagID, ResTy); } else { - auto *DC = FLoc.getAsDeclContext(); - assert(DC && DC->getAsDecl() && "not a declaration?"); + auto *FD = FLoc.castToASTNode(); auto diagID = isNoReturnFn ? diag::missing_never_call_decl : diag::missing_return_decl; - diagnose(Context, L.getEndSourceLoc(), diagID, ResTy, - DC->getAsDecl()->getDescriptiveKind()); + diagnose(Context, L.getEndSourceLoc(), diagID, ResTy, FD); } } diff --git a/lib/SILOptimizer/Mandatory/FlowIsolation.cpp b/lib/SILOptimizer/Mandatory/FlowIsolation.cpp index 26cd098062d61..41bd158bf2070 100644 --- a/lib/SILOptimizer/Mandatory/FlowIsolation.cpp +++ b/lib/SILOptimizer/Mandatory/FlowIsolation.cpp @@ -484,9 +484,9 @@ void Info::diagnoseAll(AnalysisInfo &info, bool forDeinit, VarDecl *var = cast(use)->getField(); diag.diagnose(illegalLoc.getSourceLoc(), diag::isolated_after_nonisolated, - forDeinit, var->getDescriptiveKind(), var->getName()) - .highlight(illegalLoc.getSourceRange()) - .warnUntilSwiftVersion(6); + forDeinit, var) + .highlight(illegalLoc.getSourceRange()) + .warnUntilSwiftVersion(6); // after , ... can't use self anymore, etc ... // example: diff --git a/lib/SILOptimizer/Mandatory/SendNonSendable.cpp b/lib/SILOptimizer/Mandatory/SendNonSendable.cpp index 8a34796fe6d95..145d37b14aa0f 100644 --- a/lib/SILOptimizer/Mandatory/SendNonSendable.cpp +++ b/lib/SILOptimizer/Mandatory/SendNonSendable.cpp @@ -149,17 +149,16 @@ static std::optional getDeclRefForCallee(SILInstruction *inst) { } } -static std::optional> -getSendingApplyCalleeInfo(SILInstruction *inst) { +static std::optional getSendingApplyCallee(SILInstruction *inst) { auto declRef = getDeclRefForCallee(inst); if (!declRef) return {}; auto *decl = declRef->getDecl(); - if (!decl || !decl->hasName()) + if (!decl) return {}; - return {{decl->getDescriptiveKind(), decl->getName()}}; + return decl; } static Expr *inferArgumentExprFromApplyExpr(ApplyExpr *sourceApply, @@ -672,10 +671,9 @@ class UseAfterSendDiagnosticEmitter { getFunction()); } - /// If we can find a callee decl name, return that. None otherwise. - std::optional> - getSendingCalleeInfo() const { - return getSendingApplyCalleeInfo(sendingOp->getUser()); + /// Attempts to retrieve and return the callee declaration. + std::optional getSendingCallee() const { + return getSendingApplyCallee(sendingOp->getUser()); } void @@ -697,12 +695,11 @@ class UseAfterSendDiagnosticEmitter { } } - if (auto calleeInfo = getSendingCalleeInfo()) { + if (auto callee = getSendingCallee()) { diagnoseNote( loc, diag::regionbasedisolation_named_info_send_yields_race_callee, name, descriptiveKindStr, isolationCrossing.getCalleeIsolation(), - calleeInfo->first, calleeInfo->second, - isolationCrossing.getCallerIsolation()); + callee.value(), isolationCrossing.getCallerIsolation()); } else { diagnoseNote(loc, diag::regionbasedisolation_named_info_send_yields_race, name, descriptiveKindStr, @@ -716,8 +713,7 @@ class UseAfterSendDiagnosticEmitter { emitNamedIsolationCrossingError(SILLocation loc, Identifier name, SILIsolationInfo namedValuesIsolationInfo, ApplyIsolationCrossing isolationCrossing, - DeclName calleeDeclName, - DescriptiveDeclKind calleeDeclKind) { + const ValueDecl *callee) { // Emit the short error. diagnoseError(loc, diag::regionbasedisolation_named_send_yields_race, name) .highlight(loc.getSourceRange()) @@ -736,7 +732,7 @@ class UseAfterSendDiagnosticEmitter { diagnoseNote( loc, diag::regionbasedisolation_named_info_send_yields_race_callee, name, descriptiveKindStr, isolationCrossing.getCalleeIsolation(), - calleeDeclKind, calleeDeclName, isolationCrossing.getCallerIsolation()); + callee, isolationCrossing.getCallerIsolation()); emitRequireInstDiagnostics(); } @@ -759,11 +755,10 @@ class UseAfterSendDiagnosticEmitter { .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); - if (auto calleeInfo = getSendingCalleeInfo()) { + if (auto callee = getSendingCallee()) { diagnoseNote(loc, diag::regionbasedisolation_type_use_after_send_callee, inferredType, isolationCrossing.getCalleeIsolation(), - calleeInfo->first, calleeInfo->second, - isolationCrossing.getCallerIsolation()); + callee.value(), isolationCrossing.getCallerIsolation()); } else { diagnoseNote(loc, diag::regionbasedisolation_type_use_after_send, inferredType, isolationCrossing.getCalleeIsolation(), @@ -793,10 +788,10 @@ class UseAfterSendDiagnosticEmitter { inferredType) .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); - if (auto calleeInfo = getSendingCalleeInfo()) { + if (auto callee = getSendingCallee()) { diagnoseNote(loc, diag::regionbasedisolation_typed_use_after_sending_callee, - inferredType, calleeInfo->first, calleeInfo->second); + inferredType, callee.value()); } else { diagnoseNote(loc, diag::regionbasedisolation_typed_use_after_sending, inferredType); @@ -1106,8 +1101,7 @@ struct UseAfterSendDiagnosticInferrer::AutoClosureWalker : ASTWalker { if (valueDecl->hasName()) { foundTypeInfo.diagnosticEmitter.emitNamedIsolationCrossingError( foundTypeInfo.baseLoc, targetDecl->getBaseIdentifier(), - targetDeclIsolationInfo, *isolationCrossing, - valueDecl->getName(), valueDecl->getDescriptiveKind()); + targetDeclIsolationInfo, *isolationCrossing, valueDecl); continue; } @@ -1341,10 +1335,9 @@ class SendNeverSentDiagnosticEmitter { getOperand()->getFunction()); } - /// If we can find a callee decl name, return that. None otherwise. - std::optional> - getSendingCalleeInfo() const { - return getSendingApplyCalleeInfo(sendingOperand->getUser()); + /// Attempts to retrieve and return the callee declaration. + std::optional getSendingCallee() const { + return getSendingApplyCallee(sendingOperand->getUser()); } SILLocation getLoc() const { return sendingOperand->getUser()->getLoc(); } @@ -1384,12 +1377,12 @@ class SendNeverSentDiagnosticEmitter { getIsolationRegionInfo().printForDiagnostics(os); } - if (auto calleeInfo = getSendingCalleeInfo()) { + if (auto callee = getSendingCallee()) { diagnoseNote( loc, diag::regionbasedisolation_typed_sendneversendable_via_arg_callee, descriptiveKindStr, inferredType, crossing.getCalleeIsolation(), - calleeInfo->first, calleeInfo->second); + callee.value()); } else { diagnoseNote( loc, diag::regionbasedisolation_typed_sendneversendable_via_arg, @@ -1428,11 +1421,10 @@ class SendNeverSentDiagnosticEmitter { getIsolationRegionInfo().printForDiagnostics(os); } - if (auto calleeInfo = getSendingCalleeInfo()) { + if (auto callee = getSendingCallee()) { diagnoseNote( loc, diag::regionbasedisolation_typed_tns_passed_to_sending_callee, - descriptiveKindStr, inferredType, calleeInfo->first, - calleeInfo->second); + descriptiveKindStr, inferredType, callee.value()); } else { diagnoseNote(loc, diag::regionbasedisolation_typed_tns_passed_to_sending, descriptiveKindStr, inferredType); @@ -1494,8 +1486,7 @@ class SendNeverSentDiagnosticEmitter { fArg->getType().is()) { auto diag = diag:: regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_boxed_value_task_isolated; - diagnoseNote(actualUse, diag, fArg->getDecl()->getName(), - fArg->getDecl()->getDescriptiveKind()); + diagnoseNote(actualUse, diag, fArg->getDecl()); return; } @@ -1632,12 +1623,12 @@ class SendNeverSentDiagnosticEmitter { descriptiveKindStrWithSpace.push_back(' '); } } - if (auto calleeInfo = getSendingCalleeInfo()) { + if (auto callee = getSendingCallee()) { diagnoseNote(loc, diag::regionbasedisolation_named_send_never_sendable_callee, name, descriptiveKindStrWithSpace, - isolationCrossing.getCalleeIsolation(), calleeInfo->first, - calleeInfo->second, descriptiveKindStr); + isolationCrossing.getCalleeIsolation(), callee.value(), + descriptiveKindStr); } else { diagnoseNote(loc, diag::regionbasedisolation_named_send_never_sendable, name, descriptiveKindStrWithSpace, From 0ec2527bdcf3d8ea43190b5e547b40ae605b5ea8 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Fri, 27 Jun 2025 16:21:55 -0700 Subject: [PATCH 04/10] [rbi] Wrap use ActorIsolation::printForDiagnostics with our own SILIsolationInfo::printActorIsolationForDiagnostics. I am doing this so that I can change how we emit the diagnostics just for SendNonSendable depending on if NonisolatedNonsendingByDefault is enabled without touching the rest of the compiler. This does not actually change any of the actual output though. (cherry picked from commit 4ce4fc4f954da8fe95735ae9d162bd5eb34ca8c0) --- include/swift/AST/DiagnosticsSIL.def | 24 +-- .../SILOptimizer/Utils/SILIsolationInfo.h | 8 + .../Mandatory/SendNonSendable.cpp | 186 ++++++++++++++---- lib/SILOptimizer/Utils/SILIsolationInfo.cpp | 16 +- 4 files changed, 179 insertions(+), 55 deletions(-) diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 7d4b6032dcded..6c135b3619cd2 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -983,23 +983,23 @@ GROUPED_ERROR(regionbasedisolation_type_send_yields_race, SendingRisksDataRace, (Type)) NOTE(regionbasedisolation_type_use_after_send, none, "sending value of non-Sendable type %0 to %1 callee risks causing data races between %1 and local %2 uses", - (Type, ActorIsolation, ActorIsolation)) + (Type, StringRef, StringRef)) NOTE(regionbasedisolation_type_use_after_send_callee, none, "sending value of non-Sendable type %0 to %1 %kind2 risks causing data " "races between %1 and local %3 uses", - (Type, ActorIsolation, const ValueDecl *, ActorIsolation)) + (Type, StringRef, const ValueDecl *, StringRef)) NOTE(regionbasedisolation_named_info_send_yields_race, none, "sending %1%0 to %2 callee risks causing data races between %2 and local %3 uses", - (Identifier, StringRef, ActorIsolation, ActorIsolation)) + (Identifier, StringRef, StringRef, StringRef)) NOTE(regionbasedisolation_named_info_send_yields_race_callee, none, "sending %1%0 to %2 %kind3 risks causing data races between %2 and local %4 uses", - (Identifier, StringRef, ActorIsolation, const ValueDecl *, ActorIsolation)) + (Identifier, StringRef, StringRef, const ValueDecl *, StringRef)) // Use after send closure. NOTE(regionbasedisolation_type_isolated_capture_yields_race, none, "sending value of non-Sendable type %0 to %1 closure due to closure capture risks causing races in between %1 and %2 uses", - (Type, ActorIsolation, ActorIsolation)) + (Type, StringRef, StringRef)) // Value captured in async let and reused. NOTE(regionbasedisolation_named_nonisolated_asynclet_name, none, @@ -1011,7 +1011,7 @@ NOTE(regionbasedisolation_named_value_used_after_explicit_sending, none, (Identifier)) NOTE(regionbasedisolation_named_isolated_closure_yields_race, none, "%0%1 is captured by a %2 closure. %2 uses in closure may race against later %3 uses", - (StringRef, Identifier, ActorIsolation, ActorIsolation)) + (StringRef, Identifier, StringRef, StringRef)) NOTE(regionbasedisolation_typed_use_after_sending, none, "Passing value of non-Sendable type %0 as a 'sending' argument risks causing races in between local and caller code", @@ -1025,10 +1025,10 @@ NOTE(regionbasedisolation_typed_use_after_sending_callee, none, NOTE(regionbasedisolation_named_send_never_sendable, none, "sending %1%0 to %2 callee risks causing data races between %2 and %3 uses", - (Identifier, StringRef, ActorIsolation, StringRef)) + (Identifier, StringRef, StringRef, StringRef)) NOTE(regionbasedisolation_named_send_never_sendable_callee, none, "sending %1%0 to %2 %kind3 risks causing data races between %2 and %4 uses", - (Identifier, StringRef, ActorIsolation, const ValueDecl *, StringRef)) + (Identifier, StringRef, StringRef, const ValueDecl *, StringRef)) NOTE(regionbasedisolation_named_send_into_sending_param, none, "%0%1 is passed as a 'sending' parameter; Uses in callee may race with " @@ -1077,10 +1077,10 @@ NOTE(regionbasedisolation_named_send_nt_asynclet_capture, none, (Identifier, StringRef)) NOTE(regionbasedisolation_typed_sendneversendable_via_arg, none, "sending %0 value of non-Sendable type %1 to %2 callee risks causing races in between %0 and %2 uses", - (StringRef, Type, ActorIsolation)) + (StringRef, Type, StringRef)) NOTE(regionbasedisolation_typed_sendneversendable_via_arg_callee, none, "sending %0 value of non-Sendable type %1 to %2 %kind3 risks causing races in between %0 and %2 uses", - (StringRef, Type, ActorIsolation, const ValueDecl *)) + (StringRef, Type, StringRef, const ValueDecl *)) NOTE(regionbasedisolation_isolated_conformance_introduced, none, "isolated conformance to %kind0 can be introduced here", @@ -1126,10 +1126,10 @@ NOTE(regionbasedisolation_out_sending_cannot_be_actor_isolated_note_named, none, // Example: returning main-actor isolated result to a custom-actor isolated context risks causing data races ERROR(rbi_isolation_crossing_result, none, "non-Sendable %0-typed result can not be returned from %1 %kind2 to %3 context", - (Type, ActorIsolation, const ValueDecl *, ActorIsolation)) + (Type, StringRef, const ValueDecl *, StringRef)) ERROR(rbi_isolation_crossing_result_no_decl, none, "non-Sendable %0-typed result can not be returned from %1 function to %2 context", - (Type, ActorIsolation, ActorIsolation)) + (Type, StringRef, StringRef)) NOTE(rbi_non_sendable_nominal,none, "%kind0 does not conform to the 'Sendable' protocol", (const ValueDecl *)) diff --git a/include/swift/SILOptimizer/Utils/SILIsolationInfo.h b/include/swift/SILOptimizer/Utils/SILIsolationInfo.h index c6f15400efe26..dda517d1ab5d1 100644 --- a/include/swift/SILOptimizer/Utils/SILIsolationInfo.h +++ b/include/swift/SILOptimizer/Utils/SILIsolationInfo.h @@ -549,6 +549,14 @@ class SILIsolationInfo { /// that the isolation and the isolated value match. bool isEqual(const SILIsolationInfo &other) const; + /// A helper function that prints ActorIsolation like we normally do except + /// that it prints nonisolated(nonsending) as nonisolated. This is needed in + /// certain cases when talking about use-after-free uses in send non sendable. + static void + printActorIsolationForDiagnostics(ActorIsolation iso, llvm::raw_ostream &os, + StringRef openingQuotationMark = "'", + bool asNoun = false); + void Profile(llvm::FoldingSetNodeID &id) const; private: diff --git a/lib/SILOptimizer/Mandatory/SendNonSendable.cpp b/lib/SILOptimizer/Mandatory/SendNonSendable.cpp index 145d37b14aa0f..16251e8bd732e 100644 --- a/lib/SILOptimizer/Mandatory/SendNonSendable.cpp +++ b/lib/SILOptimizer/Mandatory/SendNonSendable.cpp @@ -695,16 +695,29 @@ class UseAfterSendDiagnosticEmitter { } } + SmallString<64> calleeIsolationStr; + { + llvm::raw_svector_ostream os(calleeIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + isolationCrossing.getCalleeIsolation(), os); + } + + SmallString<64> callerIsolationStr; + { + llvm::raw_svector_ostream os(callerIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + isolationCrossing.getCallerIsolation(), os); + } + if (auto callee = getSendingCallee()) { diagnoseNote( loc, diag::regionbasedisolation_named_info_send_yields_race_callee, - name, descriptiveKindStr, isolationCrossing.getCalleeIsolation(), - callee.value(), isolationCrossing.getCallerIsolation()); + name, descriptiveKindStr, calleeIsolationStr, callee.value(), + callerIsolationStr); } else { diagnoseNote(loc, diag::regionbasedisolation_named_info_send_yields_race, - name, descriptiveKindStr, - isolationCrossing.getCalleeIsolation(), - isolationCrossing.getCallerIsolation()); + name, descriptiveKindStr, calleeIsolationStr, + callerIsolationStr); } emitRequireInstDiagnostics(); } @@ -729,10 +742,24 @@ class UseAfterSendDiagnosticEmitter { } } - diagnoseNote( - loc, diag::regionbasedisolation_named_info_send_yields_race_callee, - name, descriptiveKindStr, isolationCrossing.getCalleeIsolation(), - callee, isolationCrossing.getCallerIsolation()); + SmallString<64> calleeIsolationStr; + { + llvm::raw_svector_ostream os(calleeIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + isolationCrossing.getCalleeIsolation(), os); + } + + SmallString<64> callerIsolationStr; + { + llvm::raw_svector_ostream os(callerIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + isolationCrossing.getCallerIsolation(), os); + } + + diagnoseNote(loc, + diag::regionbasedisolation_named_info_send_yields_race_callee, + name, descriptiveKindStr, calleeIsolationStr, callee, + callerIsolationStr); emitRequireInstDiagnostics(); } @@ -755,14 +782,27 @@ class UseAfterSendDiagnosticEmitter { .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); + SmallString<64> calleeIsolationStr; + { + llvm::raw_svector_ostream os(calleeIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + isolationCrossing.getCalleeIsolation(), os); + } + + SmallString<64> callerIsolationStr; + { + llvm::raw_svector_ostream os(callerIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + isolationCrossing.getCallerIsolation(), os); + } + if (auto callee = getSendingCallee()) { diagnoseNote(loc, diag::regionbasedisolation_type_use_after_send_callee, - inferredType, isolationCrossing.getCalleeIsolation(), - callee.value(), isolationCrossing.getCallerIsolation()); + inferredType, calleeIsolationStr, callee.value(), + callerIsolationStr); } else { diagnoseNote(loc, diag::regionbasedisolation_type_use_after_send, - inferredType, isolationCrossing.getCalleeIsolation(), - isolationCrossing.getCallerIsolation()); + inferredType, calleeIsolationStr, callerIsolationStr); } emitRequireInstDiagnostics(); } @@ -817,10 +857,23 @@ class UseAfterSendDiagnosticEmitter { } } + SmallString<64> calleeIsolationStr; + { + llvm::raw_svector_ostream os(calleeIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + isolationCrossing.getCalleeIsolation(), os); + } + + SmallString<64> callerIsolationStr; + { + llvm::raw_svector_ostream os(callerIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + isolationCrossing.getCallerIsolation(), os); + } + diagnoseNote( loc, diag::regionbasedisolation_named_isolated_closure_yields_race, - descriptiveKindStr, name, isolationCrossing.getCalleeIsolation(), - isolationCrossing.getCallerIsolation()) + descriptiveKindStr, name, calleeIsolationStr, callerIsolationStr) .highlight(loc.getSourceRange()); emitRequireInstDiagnostics(); } @@ -832,10 +885,24 @@ class UseAfterSendDiagnosticEmitter { inferredType) .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); + + SmallString<64> calleeIsolationStr; + { + llvm::raw_svector_ostream os(calleeIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + isolationCrossing.getCalleeIsolation(), os); + } + + SmallString<64> callerIsolationStr; + { + llvm::raw_svector_ostream os(callerIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + isolationCrossing.getCallerIsolation(), os); + } + diagnoseNote(loc, diag::regionbasedisolation_type_isolated_capture_yields_race, - inferredType, isolationCrossing.getCalleeIsolation(), - isolationCrossing.getCallerIsolation()); + inferredType, calleeIsolationStr, callerIsolationStr); emitRequireInstDiagnostics(); } @@ -1377,16 +1444,22 @@ class SendNeverSentDiagnosticEmitter { getIsolationRegionInfo().printForDiagnostics(os); } + SmallString<64> calleeIsolationStr; + { + llvm::raw_svector_ostream os(calleeIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + crossing.getCalleeIsolation(), os); + } + if (auto callee = getSendingCallee()) { diagnoseNote( loc, diag::regionbasedisolation_typed_sendneversendable_via_arg_callee, - descriptiveKindStr, inferredType, crossing.getCalleeIsolation(), - callee.value()); + descriptiveKindStr, inferredType, calleeIsolationStr, callee.value()); } else { - diagnoseNote( - loc, diag::regionbasedisolation_typed_sendneversendable_via_arg, - descriptiveKindStr, inferredType, crossing.getCalleeIsolation()); + diagnoseNote(loc, + diag::regionbasedisolation_typed_sendneversendable_via_arg, + descriptiveKindStr, inferredType, calleeIsolationStr); } } @@ -1401,10 +1474,24 @@ class SendNeverSentDiagnosticEmitter { os << ' '; } } - diagnoseNote(loc, - diag::regionbasedisolation_named_isolated_closure_yields_race, - descriptiveKindStr, name, crossing.getCalleeIsolation(), - crossing.getCallerIsolation()) + + SmallString<64> calleeIsolationStr; + { + llvm::raw_svector_ostream os(calleeIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + crossing.getCalleeIsolation(), os); + } + + SmallString<64> callerIsolationStr; + { + llvm::raw_svector_ostream os(callerIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + crossing.getCallerIsolation(), os); + } + + diagnoseNote( + loc, diag::regionbasedisolation_named_isolated_closure_yields_race, + descriptiveKindStr, name, calleeIsolationStr, callerIsolationStr) .highlight(loc.getSourceRange()); } @@ -1623,16 +1710,23 @@ class SendNeverSentDiagnosticEmitter { descriptiveKindStrWithSpace.push_back(' '); } } + + SmallString<64> calleeIsolationStr; + { + llvm::raw_svector_ostream os(calleeIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + isolationCrossing.getCalleeIsolation(), os); + } + if (auto callee = getSendingCallee()) { diagnoseNote(loc, diag::regionbasedisolation_named_send_never_sendable_callee, - name, descriptiveKindStrWithSpace, - isolationCrossing.getCalleeIsolation(), callee.value(), - descriptiveKindStr); + name, descriptiveKindStrWithSpace, calleeIsolationStr, + callee.value(), descriptiveKindStr); } else { diagnoseNote(loc, diag::regionbasedisolation_named_send_never_sendable, - name, descriptiveKindStrWithSpace, - isolationCrossing.getCalleeIsolation(), descriptiveKindStr); + name, descriptiveKindStrWithSpace, calleeIsolationStr, + descriptiveKindStr); } } @@ -2623,17 +2717,31 @@ void NonSendableIsolationCrossingResultDiagnosticEmitter::emit() { if (!isolationCrossing) return emitUnknownPatternError(); + SmallString<64> calleeIsolationStr; + { + llvm::raw_svector_ostream os(calleeIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + isolationCrossing->getCalleeIsolation(), os); + } + + SmallString<64> callerIsolationStr; + { + llvm::raw_svector_ostream os(callerIsolationStr); + SILIsolationInfo::printActorIsolationForDiagnostics( + isolationCrossing->getCallerIsolation(), os); + } + auto type = getType(); if (getCalledDecl()) { - diagnoseError(error.op->getSourceInst(), diag::rbi_isolation_crossing_result, - type, isolationCrossing->getCalleeIsolation(), getCalledDecl(), - isolationCrossing->getCallerIsolation()) - .limitBehaviorIf(getBehaviorLimit()); + diagnoseError(error.op->getSourceInst(), + diag::rbi_isolation_crossing_result, type, calleeIsolationStr, + getCalledDecl(), callerIsolationStr) + .limitBehaviorIf(getBehaviorLimit()); } else { - diagnoseError(error.op->getSourceInst(), diag::rbi_isolation_crossing_result_no_decl, - type, isolationCrossing->getCalleeIsolation(), - isolationCrossing->getCallerIsolation()) - .limitBehaviorIf(getBehaviorLimit()); + diagnoseError(error.op->getSourceInst(), + diag::rbi_isolation_crossing_result_no_decl, type, + calleeIsolationStr, callerIsolationStr) + .limitBehaviorIf(getBehaviorLimit()); } if (type->is()) { diagnoseNote(error.op->getSourceInst(), diff --git a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp index 05da96f60ed37..b521cf6a15312 100644 --- a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp +++ b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp @@ -1237,6 +1237,14 @@ void SILIsolationInfo::printOptions(llvm::raw_ostream &os) const { llvm::interleave(data, os, ", "); } +/// We want to treat nonisolated(nonsending) just like nonisolated. So we use +/// this with composition. +void SILIsolationInfo::printActorIsolationForDiagnostics( + ActorIsolation iso, llvm::raw_ostream &os, StringRef openingQuotationMark, + bool asNoun) { + return iso.printForDiagnostics(os, openingQuotationMark, asNoun); +} + void SILIsolationInfo::print(llvm::raw_ostream &os) const { switch (Kind(*this)) { case Unknown: @@ -1284,7 +1292,7 @@ void SILIsolationInfo::print(llvm::raw_ostream &os) const { } } - getActorIsolation().printForDiagnostics(os); + printActorIsolationForDiagnostics(getActorIsolation(), os); printOptions(os); return; case Task: @@ -1406,7 +1414,7 @@ void SILIsolationInfo::printForDiagnostics(llvm::raw_ostream &os) const { } } - getActorIsolation().printForDiagnostics(os); + printActorIsolationForDiagnostics(getActorIsolation(), os); return; case Task: os << "task-isolated"; @@ -1449,7 +1457,7 @@ void SILIsolationInfo::printForCodeDiagnostic(llvm::raw_ostream &os) const { } } - getActorIsolation().printForDiagnostics(os); + printActorIsolationForDiagnostics(getActorIsolation(), os); os << " code"; return; case Task: @@ -1498,7 +1506,7 @@ void SILIsolationInfo::printForOneLineLogging(llvm::raw_ostream &os) const { } } - getActorIsolation().printForDiagnostics(os); + printActorIsolationForDiagnostics(getActorIsolation(), os); printOptions(os); return; case Task: From ca8cdc1fd77012d3044ec1e4d166b9e3bb5788e2 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 2 Jul 2025 09:55:38 -0700 Subject: [PATCH 05/10] [rbi] Thread through a SILFunction into print routines so we can access LangOpts.Features so we can change how we print based off of NonisolatedNonsendingByDefault. We do not actually use this information yet though... This is just to ease review. (cherry picked from commit 4433ab8d81c3ea3e76320e4bd8c63f09b4db2954) --- .../SILOptimizer/Analysis/RegionAnalysis.h | 28 +++---- .../SILOptimizer/Utils/SILIsolationInfo.h | 59 +++++---------- lib/SILOptimizer/Analysis/RegionAnalysis.cpp | 30 +++++--- .../Mandatory/SendNonSendable.cpp | 75 ++++++++++--------- lib/SILOptimizer/Utils/PartitionUtils.cpp | 4 +- lib/SILOptimizer/Utils/SILIsolationInfo.cpp | 34 +++++---- 6 files changed, 115 insertions(+), 115 deletions(-) diff --git a/include/swift/SILOptimizer/Analysis/RegionAnalysis.h b/include/swift/SILOptimizer/Analysis/RegionAnalysis.h index 7b81e1a3356df..eefdf5f47bbf9 100644 --- a/include/swift/SILOptimizer/Analysis/RegionAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/RegionAnalysis.h @@ -179,16 +179,16 @@ class regionanalysisimpl::TrackableValueState { void removeFlag(TrackableValueFlag flag) { flagSet -= flag; } - void print(llvm::raw_ostream &os) const { + void print(SILFunction *fn, llvm::raw_ostream &os) const { os << "TrackableValueState[id: " << id << "][is_no_alias: " << (isNoAlias() ? "yes" : "no") << "][is_sendable: " << (isSendable() ? "yes" : "no") << "][region_value_kind: "; - getIsolationRegionInfo().printForOneLineLogging(os); + getIsolationRegionInfo().printForOneLineLogging(fn, os); os << "]."; } - SWIFT_DEBUG_DUMP { print(llvm::dbgs()); } + SWIFT_DEBUG_DUMPER(dump(SILFunction *fn)) { print(fn, llvm::dbgs()); } private: bool hasIsolationRegionInfo() const { return bool(regionInfo); } @@ -249,26 +249,26 @@ class regionanalysisimpl::TrackableValue { /// parameter. bool isSendingParameter() const; - void printIsolationInfo(SmallString<64> &outString) const { + void printIsolationInfo(SILFunction *fn, SmallString<64> &outString) const { llvm::raw_svector_ostream os(outString); - getIsolationRegionInfo().printForDiagnostics(os); + getIsolationRegionInfo().printForDiagnostics(fn, os); } - void print(llvm::raw_ostream &os) const { + void print(SILFunction *fn, llvm::raw_ostream &os) const { os << "TrackableValue. State: "; - valueState.print(os); + valueState.print(fn, os); os << "\n Rep Value: "; getRepresentative().print(os); } - void printVerbose(llvm::raw_ostream &os) const { + void printVerbose(SILFunction *fn, llvm::raw_ostream &os) const { os << "TrackableValue. State: "; - valueState.print(os); + valueState.print(fn, os); os << "\n Rep Value: " << getRepresentative(); } - SWIFT_DEBUG_DUMP { - print(llvm::dbgs()); + SWIFT_DEBUG_DUMPER(dump(SILFunction *fn)) { + print(fn, llvm::dbgs()); llvm::dbgs() << '\n'; } }; @@ -288,8 +288,8 @@ struct regionanalysisimpl::TrackableValueLookupResult { /// TrackableValue. std::optional base; - void print(llvm::raw_ostream &os) const; - SWIFT_DEBUG_DUMP { print(llvm::dbgs()); } + void print(SILFunction *fn, llvm::raw_ostream &os) const; + SWIFT_DEBUG_DUMPER(dumper(SILFunction *fn)) { print(fn, llvm::dbgs()); } }; class RegionAnalysis; @@ -390,6 +390,8 @@ class RegionAnalysisValueMap { return getUnderlyingTrackedValue(value).value; } + SILFunction *getFunction() const { return fn; } + /// Returns the value for this instruction if it isn't a fake "represenative /// value" to inject actor isolatedness. Asserts in such a case. SILValue getRepresentative(Element trackableValueID) const; diff --git a/include/swift/SILOptimizer/Utils/SILIsolationInfo.h b/include/swift/SILOptimizer/Utils/SILIsolationInfo.h index dda517d1ab5d1..4530c3cf9fb35 100644 --- a/include/swift/SILOptimizer/Utils/SILIsolationInfo.h +++ b/include/swift/SILOptimizer/Utils/SILIsolationInfo.h @@ -337,16 +337,16 @@ class SILIsolationInfo { return self; } - void print(llvm::raw_ostream &os) const; + void print(SILFunction *fn, llvm::raw_ostream &os) const; /// Print a textual representation of the text info that is meant to be /// included in other logging output for types that compose with /// SILIsolationInfo. As a result, we only print state that can fit on /// one line. - void printForOneLineLogging(llvm::raw_ostream &os) const; + void printForOneLineLogging(SILFunction *fn, llvm::raw_ostream &os) const; - SWIFT_DEBUG_DUMP { - print(llvm::dbgs()); + SWIFT_DEBUG_DUMPER(dump(SILFunction *fn)) { + print(fn, llvm::dbgs()); llvm::dbgs() << '\n'; } @@ -355,12 +355,12 @@ class SILIsolationInfo { /// /// We do this programatically since task-isolated code needs a very different /// form of diagnostic than other cases. - void printForCodeDiagnostic(llvm::raw_ostream &os) const; + void printForCodeDiagnostic(SILFunction *fn, llvm::raw_ostream &os) const; - void printForDiagnostics(llvm::raw_ostream &os) const; + void printForDiagnostics(SILFunction *fn, llvm::raw_ostream &os) const; - SWIFT_DEBUG_DUMPER(dumpForDiagnostics()) { - printForDiagnostics(llvm::dbgs()); + SWIFT_DEBUG_DUMPER(dumpForDiagnostics(SILFunction *fn)) { + printForDiagnostics(fn, llvm::dbgs()); llvm::dbgs() << '\n'; } @@ -552,10 +552,9 @@ class SILIsolationInfo { /// A helper function that prints ActorIsolation like we normally do except /// that it prints nonisolated(nonsending) as nonisolated. This is needed in /// certain cases when talking about use-after-free uses in send non sendable. - static void - printActorIsolationForDiagnostics(ActorIsolation iso, llvm::raw_ostream &os, - StringRef openingQuotationMark = "'", - bool asNoun = false); + static void printActorIsolationForDiagnostics( + SILFunction *fn, ActorIsolation iso, llvm::raw_ostream &os, + StringRef openingQuotationMark = "'", bool asNoun = false); void Profile(llvm::FoldingSetNodeID &id) const; @@ -620,43 +619,25 @@ class SILDynamicMergedIsolationInfo { SILIsolationInfo::getDisconnected(isUnsafeNonIsolated)); } - SWIFT_DEBUG_DUMP { innerInfo.dump(); } + SWIFT_DEBUG_DUMPER(dump(SILFunction *fn)) { innerInfo.dump(fn); } - void printForDiagnostics(llvm::raw_ostream &os) const { - innerInfo.printForDiagnostics(os); + void printForDiagnostics(SILFunction *fn, llvm::raw_ostream &os) const { + innerInfo.printForDiagnostics(fn, os); } - SWIFT_DEBUG_DUMPER(dumpForDiagnostics()) { - innerInfo.dumpForDiagnostics(); + SWIFT_DEBUG_DUMPER(dumpForDiagnostics(SILFunction *fn)) { + innerInfo.dumpForDiagnostics(fn); } - void printForCodeDiagnostic(llvm::raw_ostream &os) const { - innerInfo.printForCodeDiagnostic(os); + void printForCodeDiagnostic(SILFunction *fn, llvm::raw_ostream &os) const { + innerInfo.printForCodeDiagnostic(fn, os); } - void printForOneLineLogging(llvm::raw_ostream &os) const { - innerInfo.printForOneLineLogging(os); + void printForOneLineLogging(SILFunction *fn, llvm::raw_ostream &os) const { + innerInfo.printForOneLineLogging(fn, os); } }; } // namespace swift -namespace llvm { - -inline llvm::raw_ostream & -operator<<(llvm::raw_ostream &os, - const swift::SILIsolationInfo &isolationInfo) { - isolationInfo.printForOneLineLogging(os); - return os; -} - -inline llvm::raw_ostream & -operator<<(llvm::raw_ostream &os, - const swift::SILDynamicMergedIsolationInfo &isolationInfo) { - isolationInfo.printForOneLineLogging(os); - return os; -} - -} // namespace llvm - #endif diff --git a/lib/SILOptimizer/Analysis/RegionAnalysis.cpp b/lib/SILOptimizer/Analysis/RegionAnalysis.cpp index 79be3cf57cb2e..1d19efe5c1144 100644 --- a/lib/SILOptimizer/Analysis/RegionAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/RegionAnalysis.cpp @@ -820,7 +820,7 @@ void RegionAnalysisValueMap::print(llvm::raw_ostream &os) const { for (auto p : temp) { os << "%%" << p.first << ": "; auto value = getValueForId(Element(p.first)); - value->print(os); + value->print(getFunction(), os); } #endif } @@ -1127,12 +1127,13 @@ bool TrackableValue::isSendingParameter() const { // MARK: TrackableValueLookupResult //===----------------------------------------------------------------------===// -void TrackableValueLookupResult::print(llvm::raw_ostream &os) const { +void TrackableValueLookupResult::print(SILFunction *fn, + llvm::raw_ostream &os) const { os << "Value:\n"; - value.print(os); + value.print(fn, os); if (base) { os << "Base:\n"; - base->print(os); + base->print(fn, os); } } @@ -1618,6 +1619,11 @@ struct PartitionOpBuilder { /// generating partition ops. SmallVector currentInstPartitionOps; + SILFunction *getFunction() const { + assert(currentInst); + return currentInst->getFunction(); + } + void reset(SILInstruction *inst) { currentInst = inst; currentInstPartitionOps.clear(); @@ -1978,7 +1984,8 @@ class PartitionOpTranslator { isNonSendableType(val->getType())) { auto trackVal = getTrackableValue(val, true); (void)trackVal; - REGIONBASEDISOLATION_LOG(trackVal.print(llvm::dbgs())); + REGIONBASEDISOLATION_LOG( + trackVal.print(val->getFunction(), llvm::dbgs())); continue; } if (auto *pbi = dyn_cast(val)) { @@ -2055,7 +2062,7 @@ class PartitionOpTranslator { // send list and to the region join list. REGIONBASEDISOLATION_LOG( llvm::dbgs() << " %%" << value.getID() << ": "; - value.print(llvm::dbgs()); llvm::dbgs() << *arg); + value.print(function, llvm::dbgs()); llvm::dbgs() << *arg); nonSendableJoinedIndices.push_back(value.getID()); } else { REGIONBASEDISOLATION_LOG(llvm::dbgs() << " Sendable: " << *arg); @@ -2228,14 +2235,15 @@ class PartitionOpTranslator { REGIONBASEDISOLATION_LOG( llvm::dbgs() << "Merge Failure!\n" << "Original Info: "; - if (originalMergedInfo) - originalMergedInfo->printForDiagnostics(llvm::dbgs()); + if (originalMergedInfo) originalMergedInfo->printForDiagnostics( + builder.getFunction(), llvm::dbgs()); else llvm::dbgs() << "nil"; llvm::dbgs() << "\nValue Rep: " << value.getRepresentative().getValue(); llvm::dbgs() << "Original Src: " << src; llvm::dbgs() << "Value Info: "; - value.getIsolationRegionInfo().printForDiagnostics(llvm::dbgs()); + value.getIsolationRegionInfo().printForDiagnostics( + builder.getFunction(), llvm::dbgs()); llvm::dbgs() << "\n"); builder.addUnknownPatternError(src); continue; @@ -3220,7 +3228,7 @@ void PartitionOpBuilder::print(llvm::raw_ostream &os) const { auto trackableValue = translator->getValueForId(opArg); assert(trackableValue); llvm::dbgs() << "State: %%" << opArg << ". "; - trackableValue->getValueState().print(llvm::dbgs()); + trackableValue->getValueState().print(getFunction(), llvm::dbgs()); llvm::dbgs() << "\n Rep Value: " << trackableValue->getRepresentative(); if (auto value = trackableValue->getRepresentative().maybeGetValue()) { @@ -4310,7 +4318,7 @@ static FunctionTest RegionAnalysisValueMap valueMap(&function); auto value = arguments.takeValue(); auto trackableValue = valueMap.getTrackableValue(value); - trackableValue.print(llvm::outs()); + trackableValue.print(&function, llvm::outs()); llvm::outs() << '\n'; }); diff --git a/lib/SILOptimizer/Mandatory/SendNonSendable.cpp b/lib/SILOptimizer/Mandatory/SendNonSendable.cpp index 16251e8bd732e..f9e000064ef35 100644 --- a/lib/SILOptimizer/Mandatory/SendNonSendable.cpp +++ b/lib/SILOptimizer/Mandatory/SendNonSendable.cpp @@ -690,7 +690,7 @@ class UseAfterSendDiagnosticEmitter { { if (!namedValuesIsolationInfo.isDisconnected()) { llvm::raw_svector_ostream os(descriptiveKindStr); - namedValuesIsolationInfo.printForDiagnostics(os); + namedValuesIsolationInfo.printForDiagnostics(getFunction(), os); os << ' '; } } @@ -699,14 +699,14 @@ class UseAfterSendDiagnosticEmitter { { llvm::raw_svector_ostream os(calleeIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - isolationCrossing.getCalleeIsolation(), os); + getFunction(), isolationCrossing.getCalleeIsolation(), os); } SmallString<64> callerIsolationStr; { llvm::raw_svector_ostream os(callerIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - isolationCrossing.getCallerIsolation(), os); + getFunction(), isolationCrossing.getCallerIsolation(), os); } if (auto callee = getSendingCallee()) { @@ -737,7 +737,7 @@ class UseAfterSendDiagnosticEmitter { { if (!namedValuesIsolationInfo.isDisconnected()) { llvm::raw_svector_ostream os(descriptiveKindStr); - namedValuesIsolationInfo.printForDiagnostics(os); + namedValuesIsolationInfo.printForDiagnostics(getFunction(), os); os << ' '; } } @@ -746,14 +746,14 @@ class UseAfterSendDiagnosticEmitter { { llvm::raw_svector_ostream os(calleeIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - isolationCrossing.getCalleeIsolation(), os); + getFunction(), isolationCrossing.getCalleeIsolation(), os); } SmallString<64> callerIsolationStr; { llvm::raw_svector_ostream os(callerIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - isolationCrossing.getCallerIsolation(), os); + getFunction(), isolationCrossing.getCallerIsolation(), os); } diagnoseNote(loc, @@ -786,14 +786,14 @@ class UseAfterSendDiagnosticEmitter { { llvm::raw_svector_ostream os(calleeIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - isolationCrossing.getCalleeIsolation(), os); + getFunction(), isolationCrossing.getCalleeIsolation(), os); } SmallString<64> callerIsolationStr; { llvm::raw_svector_ostream os(callerIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - isolationCrossing.getCallerIsolation(), os); + getFunction(), isolationCrossing.getCallerIsolation(), os); } if (auto callee = getSendingCallee()) { @@ -852,7 +852,7 @@ class UseAfterSendDiagnosticEmitter { { if (!namedValuesIsolationInfo.isDisconnected()) { llvm::raw_svector_ostream os(descriptiveKindStr); - namedValuesIsolationInfo.printForDiagnostics(os); + namedValuesIsolationInfo.printForDiagnostics(getFunction(), os); os << ' '; } } @@ -861,14 +861,14 @@ class UseAfterSendDiagnosticEmitter { { llvm::raw_svector_ostream os(calleeIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - isolationCrossing.getCalleeIsolation(), os); + getFunction(), isolationCrossing.getCalleeIsolation(), os); } SmallString<64> callerIsolationStr; { llvm::raw_svector_ostream os(callerIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - isolationCrossing.getCallerIsolation(), os); + getFunction(), isolationCrossing.getCallerIsolation(), os); } diagnoseNote( @@ -890,14 +890,14 @@ class UseAfterSendDiagnosticEmitter { { llvm::raw_svector_ostream os(calleeIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - isolationCrossing.getCalleeIsolation(), os); + getFunction(), isolationCrossing.getCalleeIsolation(), os); } SmallString<64> callerIsolationStr; { llvm::raw_svector_ostream os(callerIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - isolationCrossing.getCallerIsolation(), os); + getFunction(), isolationCrossing.getCallerIsolation(), os); } diagnoseNote(loc, @@ -1441,14 +1441,14 @@ class SendNeverSentDiagnosticEmitter { SmallString<64> descriptiveKindStr; { llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); + getIsolationRegionInfo().printForDiagnostics(getFunction(), os); } SmallString<64> calleeIsolationStr; { llvm::raw_svector_ostream os(calleeIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - crossing.getCalleeIsolation(), os); + getFunction(), crossing.getCalleeIsolation(), os); } if (auto callee = getSendingCallee()) { @@ -1470,7 +1470,7 @@ class SendNeverSentDiagnosticEmitter { { if (!getIsolationRegionInfo().isDisconnected()) { llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); + getIsolationRegionInfo().printForDiagnostics(getFunction(), os); os << ' '; } } @@ -1479,14 +1479,14 @@ class SendNeverSentDiagnosticEmitter { { llvm::raw_svector_ostream os(calleeIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - crossing.getCalleeIsolation(), os); + getFunction(), crossing.getCalleeIsolation(), os); } SmallString<64> callerIsolationStr; { llvm::raw_svector_ostream os(callerIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - crossing.getCallerIsolation(), os); + getFunction(), crossing.getCallerIsolation(), os); } diagnoseNote( @@ -1505,7 +1505,7 @@ class SendNeverSentDiagnosticEmitter { SmallString<64> descriptiveKindStr; { llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); + getIsolationRegionInfo().printForDiagnostics(getFunction(), os); } if (auto callee = getSendingCallee()) { @@ -1527,7 +1527,8 @@ class SendNeverSentDiagnosticEmitter { SmallString<64> descriptiveKindStr; { llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().getIsolationInfo().printForCodeDiagnostic(os); + getIsolationRegionInfo().getIsolationInfo().printForCodeDiagnostic( + getFunction(), os); } diagnoseError(partialApplyOp, @@ -1539,7 +1540,8 @@ class SendNeverSentDiagnosticEmitter { descriptiveKindStr.clear(); { llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().getIsolationInfo().printForDiagnostics(os); + getIsolationRegionInfo().getIsolationInfo().printForDiagnostics( + getFunction(), os); } diagnoseNote(actualUse, diag::regionbasedisolation_closure_captures_actor, fArg->getDecl()->getName(), descriptiveKindStr); @@ -1558,7 +1560,8 @@ class SendNeverSentDiagnosticEmitter { SmallString<64> descriptiveKindStr; { llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().getIsolationInfo().printForCodeDiagnostic(os); + getIsolationRegionInfo().getIsolationInfo().printForCodeDiagnostic( + getFunction(), os); } diagnoseError(partialApplyOp, @@ -1586,7 +1589,7 @@ class SendNeverSentDiagnosticEmitter { descriptiveKindStr.clear(); { llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); + getIsolationRegionInfo().printForDiagnostics(getFunction(), os); } auto diag = diag:: @@ -1607,7 +1610,7 @@ class SendNeverSentDiagnosticEmitter { SmallString<64> descriptiveKindStr; { llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo()->printForCodeDiagnostic(os); + getIsolationRegionInfo()->printForCodeDiagnostic(getFunction(), os); } auto emitMainError = [&] { @@ -1643,7 +1646,7 @@ class SendNeverSentDiagnosticEmitter { descriptiveKindStr.clear(); { llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); + getIsolationRegionInfo().printForDiagnostics(getFunction(), os); } auto diag = diag:: regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value_region; @@ -1688,7 +1691,7 @@ class SendNeverSentDiagnosticEmitter { SmallString<64> descriptiveKindStr; { llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); + getIsolationRegionInfo().printForDiagnostics(getFunction(), os); } diagnoseNote(loc, diag::regionbasedisolation_named_send_nt_asynclet_capture, @@ -1704,7 +1707,7 @@ class SendNeverSentDiagnosticEmitter { if (!getIsolationRegionInfo().isDisconnected()) { { llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); + getIsolationRegionInfo().printForDiagnostics(getFunction(), os); } descriptiveKindStrWithSpace = descriptiveKindStr; descriptiveKindStrWithSpace.push_back(' '); @@ -1715,7 +1718,7 @@ class SendNeverSentDiagnosticEmitter { { llvm::raw_svector_ostream os(calleeIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - isolationCrossing.getCalleeIsolation(), os); + getFunction(), isolationCrossing.getCalleeIsolation(), os); } if (auto callee = getSendingCallee()) { @@ -1737,7 +1740,7 @@ class SendNeverSentDiagnosticEmitter { { if (!getIsolationRegionInfo().isDisconnected()) { llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); + getIsolationRegionInfo().printForDiagnostics(getFunction(), os); os << ' '; } } @@ -1753,7 +1756,7 @@ class SendNeverSentDiagnosticEmitter { if (!getIsolationRegionInfo().isDisconnected()) { { llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); + getIsolationRegionInfo().printForDiagnostics(getFunction(), os); } descriptiveKindStrWithSpace = descriptiveKindStr; descriptiveKindStrWithSpace.push_back(' '); @@ -2316,7 +2319,7 @@ void InOutSendingNotDisconnectedDiagnosticEmitter::emit() { SmallString<64> descriptiveKindStr; { llvm::raw_svector_ostream os(descriptiveKindStr); - actorIsolatedRegionInfo.printForDiagnostics(os); + actorIsolatedRegionInfo.printForDiagnostics(getFunction(), os); os << ' '; } @@ -2476,7 +2479,7 @@ void AssignIsolatedIntoSendingResultDiagnosticEmitter::emit() { SmallString<64> descriptiveKindStr; { llvm::raw_svector_ostream os(descriptiveKindStr); - isolatedValueIsolationRegionInfo.printForDiagnostics(os); + isolatedValueIsolationRegionInfo.printForDiagnostics(getFunction(), os); } // Grab the var name if we can find it. @@ -2601,6 +2604,10 @@ struct NonSendableIsolationCrossingResultDiagnosticEmitter { : valueMap(valueMap), error(error), representative(valueMap.getRepresentative(error.returnValueElement)) {} + SILFunction *getFunction() const { + return error.op->getSourceInst()->getFunction(); + } + void emit(); ASTContext &getASTContext() const { @@ -2721,14 +2728,14 @@ void NonSendableIsolationCrossingResultDiagnosticEmitter::emit() { { llvm::raw_svector_ostream os(calleeIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - isolationCrossing->getCalleeIsolation(), os); + getFunction(), isolationCrossing->getCalleeIsolation(), os); } SmallString<64> callerIsolationStr; { llvm::raw_svector_ostream os(callerIsolationStr); SILIsolationInfo::printActorIsolationForDiagnostics( - isolationCrossing->getCallerIsolation(), os); + getFunction(), isolationCrossing->getCallerIsolation(), os); } auto type = getType(); diff --git a/lib/SILOptimizer/Utils/PartitionUtils.cpp b/lib/SILOptimizer/Utils/PartitionUtils.cpp index 4980743c20278..55a75e42f548c 100644 --- a/lib/SILOptimizer/Utils/PartitionUtils.cpp +++ b/lib/SILOptimizer/Utils/PartitionUtils.cpp @@ -46,7 +46,7 @@ void PartitionOpError::SentNeverSendableError::print( << " ID: %%" << sentElement << "\n" << " Rep: " << *info.getRepresentative(sentElement) << " Dynamic Isolation Region: "; - isolationRegionInfo.printForOneLineLogging(os); + isolationRegionInfo.printForOneLineLogging(info.getFunction(), os); os << '\n'; if (auto isolatedValue = isolationRegionInfo->maybeGetIsolatedValue()) { os << " Isolated Value: " << isolatedValue; @@ -90,7 +90,7 @@ void PartitionOpError::InOutSendingNotDisconnectedAtExitError::print( << " ID: %%" << inoutSendingElement << "\n" << " Rep: " << valueMap.getRepresentativeValue(inoutSendingElement) << " Dynamic Isolation Region: "; - isolationInfo.printForOneLineLogging(os); + isolationInfo.printForOneLineLogging(valueMap.getFunction(), os); os << '\n'; } diff --git a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp index b521cf6a15312..da09a1f32b5d5 100644 --- a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp +++ b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp @@ -1237,15 +1237,13 @@ void SILIsolationInfo::printOptions(llvm::raw_ostream &os) const { llvm::interleave(data, os, ", "); } -/// We want to treat nonisolated(nonsending) just like nonisolated. So we use -/// this with composition. void SILIsolationInfo::printActorIsolationForDiagnostics( - ActorIsolation iso, llvm::raw_ostream &os, StringRef openingQuotationMark, - bool asNoun) { + SILFunction *fn, ActorIsolation iso, llvm::raw_ostream &os, + StringRef openingQuotationMark, bool asNoun) { return iso.printForDiagnostics(os, openingQuotationMark, asNoun); } -void SILIsolationInfo::print(llvm::raw_ostream &os) const { +void SILIsolationInfo::print(SILFunction *fn, llvm::raw_ostream &os) const { switch (Kind(*this)) { case Unknown: os << "unknown"; @@ -1292,7 +1290,7 @@ void SILIsolationInfo::print(llvm::raw_ostream &os) const { } } - printActorIsolationForDiagnostics(getActorIsolation(), os); + printActorIsolationForDiagnostics(fn, getActorIsolation(), os); printOptions(os); return; case Task: @@ -1379,7 +1377,8 @@ void SILIsolationInfo::Profile(llvm::FoldingSetNodeID &id) const { } } -void SILIsolationInfo::printForDiagnostics(llvm::raw_ostream &os) const { +void SILIsolationInfo::printForDiagnostics(SILFunction *fn, + llvm::raw_ostream &os) const { switch (Kind(*this)) { case Unknown: llvm::report_fatal_error("Printing unknown for diagnostics?!"); @@ -1414,7 +1413,7 @@ void SILIsolationInfo::printForDiagnostics(llvm::raw_ostream &os) const { } } - printActorIsolationForDiagnostics(getActorIsolation(), os); + printActorIsolationForDiagnostics(fn, getActorIsolation(), os); return; case Task: os << "task-isolated"; @@ -1422,7 +1421,8 @@ void SILIsolationInfo::printForDiagnostics(llvm::raw_ostream &os) const { } } -void SILIsolationInfo::printForCodeDiagnostic(llvm::raw_ostream &os) const { +void SILIsolationInfo::printForCodeDiagnostic(SILFunction *fn, + llvm::raw_ostream &os) const { switch (Kind(*this)) { case Unknown: llvm::report_fatal_error("Printing unknown for code diagnostic?!"); @@ -1457,7 +1457,7 @@ void SILIsolationInfo::printForCodeDiagnostic(llvm::raw_ostream &os) const { } } - printActorIsolationForDiagnostics(getActorIsolation(), os); + printActorIsolationForDiagnostics(fn, getActorIsolation(), os); os << " code"; return; case Task: @@ -1466,7 +1466,8 @@ void SILIsolationInfo::printForCodeDiagnostic(llvm::raw_ostream &os) const { } } -void SILIsolationInfo::printForOneLineLogging(llvm::raw_ostream &os) const { +void SILIsolationInfo::printForOneLineLogging(SILFunction *fn, + llvm::raw_ostream &os) const { switch (Kind(*this)) { case Unknown: os << "unknown"; @@ -1506,7 +1507,7 @@ void SILIsolationInfo::printForOneLineLogging(llvm::raw_ostream &os) const { } } - printActorIsolationForDiagnostics(getActorIsolation(), os); + printActorIsolationForDiagnostics(fn, getActorIsolation(), os); printOptions(os); return; case Task: @@ -1713,7 +1714,8 @@ static FunctionTest SILIsolationInfo::get(value); llvm::outs() << "Input Value: " << *value; llvm::outs() << "Isolation: "; - info.printForOneLineLogging(llvm::outs()); + info.printForOneLineLogging(&function, + llvm::outs()); llvm::outs() << "\n"; }); @@ -1733,13 +1735,13 @@ static FunctionTest IsolationMergeTest( mergedInfo = mergedInfo->merge(secondValueInfo); llvm::outs() << "First Value: " << *firstValue; llvm::outs() << "First Isolation: "; - firstValueInfo.printForOneLineLogging(llvm::outs()); + firstValueInfo.printForOneLineLogging(&function, llvm::outs()); llvm::outs() << "\nSecond Value: " << *secondValue; llvm::outs() << "Second Isolation: "; - secondValueInfo.printForOneLineLogging(llvm::outs()); + secondValueInfo.printForOneLineLogging(&function, llvm::outs()); llvm::outs() << "\nMerged Isolation: "; if (mergedInfo) { - mergedInfo->printForOneLineLogging(llvm::outs()); + mergedInfo->printForOneLineLogging(&function, llvm::outs()); } else { llvm::outs() << "Merge failure!"; } From 85fafa5b1ee5e27cf6a727cb06d255958bfb879a Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 2 Jul 2025 09:01:17 -0700 Subject: [PATCH 06/10] [rbi] Begin tracking if a function argument is from a nonisolated(nonsending) parameter and adjust printing as appropriate. Specifically in terms of printing, if NonisolatedNonsendingByDefault is enabled, we print out things as nonisolated/task-isolated and @concurrent/@concurrent task-isolated. If said feature is disabled, we print out things as nonisolated(nonsending)/nonisolated(nonsending) task-isolated and nonisolated/task-isolated. This ensures in the default case, diagnostics do not change and we always print out things to match the expected meaning of nonisolated depending on the mode. I also updated the tests as appropriate/added some more tests/added to the SendNonSendable education notes information about this. (cherry picked from commit 14634b684737a103dd20d25eaa8fc4550a4b5fe4) --- .../SILOptimizer/Utils/SILIsolationInfo.h | 23 ++++ lib/SILOptimizer/Utils/SILIsolationInfo.cpp | 62 ++++++++- test/ClangImporter/regionbasedisolation.swift | 5 +- .../nonisolated_inherits_isolation.swift | 22 ++-- test/Concurrency/transfernonsendable.swift | 8 ++ .../transfernonsendable_asynclet.swift | 124 +++++++++++------- .../transfernonsendable_initializers.swift | 7 +- .../transfernonsendable_sending_results.swift | 13 +- .../caller_isolation_inherit.swift | 24 ++-- 9 files changed, 209 insertions(+), 79 deletions(-) diff --git a/include/swift/SILOptimizer/Utils/SILIsolationInfo.h b/include/swift/SILOptimizer/Utils/SILIsolationInfo.h index 4530c3cf9fb35..c7bc151a7635d 100644 --- a/include/swift/SILOptimizer/Utils/SILIsolationInfo.h +++ b/include/swift/SILOptimizer/Utils/SILIsolationInfo.h @@ -185,6 +185,10 @@ class SILIsolationInfo { /// parameter and should be allowed to merge into a self parameter. UnappliedIsolatedAnyParameter = 0x2, + /// If set, this was a TaskIsolated value from a nonisolated(nonsending) + /// parameter. + NonisolatedNonsendingTaskIsolated = 0x4, + /// The maximum number of bits used by a Flag. MaxNumBits = 3, }; @@ -317,6 +321,25 @@ class SILIsolationInfo { return result; } + bool isNonisolatedNonsendingTaskIsolated() const { + return getOptions().contains(Flag::NonisolatedNonsendingTaskIsolated); + } + + SILIsolationInfo + withNonisolatedNonsendingTaskIsolated(bool newValue = true) const { + assert(*this && "Cannot be unknown"); + assert(isTaskIsolated() && "Can only be task isolated"); + auto self = *this; + if (newValue) { + self.options = + (self.getOptions() | Flag::NonisolatedNonsendingTaskIsolated).toRaw(); + } else { + self.options = self.getOptions().toRaw() & + ~Options(Flag::NonisolatedNonsendingTaskIsolated).toRaw(); + } + return self; + } + /// Returns true if this actor isolation is derived from an unapplied /// isolation parameter. When merging, we allow for this to be merged with a /// more specific isolation kind. diff --git a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp index da09a1f32b5d5..2a08f166c0cce 100644 --- a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp +++ b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp @@ -938,6 +938,12 @@ SILIsolationInfo SILIsolationInfo::get(SILInstruction *inst) { /// Consider non-Sendable metatypes to be task-isolated, so they cannot cross /// into another isolation domain. if (auto *mi = dyn_cast(inst)) { + if (auto funcIsolation = mi->getFunction()->getActorIsolation(); + funcIsolation && funcIsolation->isCallerIsolationInheriting()) { + return SILIsolationInfo::getTaskIsolated(mi) + .withNonisolatedNonsendingTaskIsolated(true); + } + return SILIsolationInfo::getTaskIsolated(mi); } @@ -1003,7 +1009,8 @@ SILIsolationInfo SILIsolationInfo::get(SILArgument *arg) { // task isolated. if (auto funcIsolation = fArg->getFunction()->getActorIsolation(); funcIsolation && funcIsolation->isCallerIsolationInheriting()) { - return SILIsolationInfo::getTaskIsolated(fArg); + return SILIsolationInfo::getTaskIsolated(fArg) + .withNonisolatedNonsendingTaskIsolated(true); } auto astType = isolatedArg->getType().getASTType(); @@ -1240,6 +1247,21 @@ void SILIsolationInfo::printOptions(llvm::raw_ostream &os) const { void SILIsolationInfo::printActorIsolationForDiagnostics( SILFunction *fn, ActorIsolation iso, llvm::raw_ostream &os, StringRef openingQuotationMark, bool asNoun) { + // If we have NonisolatedNonsendingByDefault enabled, we need to return + // @concurrent for nonisolated and nonisolated for caller isolation inherited. + if (fn->isAsync() && fn->getASTContext().LangOpts.hasFeature( + Feature::NonisolatedNonsendingByDefault)) { + if (iso.isCallerIsolationInheriting()) { + os << "nonisolated"; + return; + } + + if (iso.isNonisolated()) { + os << "@concurrent"; + return; + } + } + return iso.printForDiagnostics(os, openingQuotationMark, asNoun); } @@ -1361,6 +1383,7 @@ bool SILIsolationInfo::isEqual(const SILIsolationInfo &other) const { void SILIsolationInfo::Profile(llvm::FoldingSetNodeID &id) const { id.AddInteger(getKind()); + id.AddInteger(getOptions().toRaw()); switch (getKind()) { case Unknown: case Disconnected: @@ -1416,6 +1439,21 @@ void SILIsolationInfo::printForDiagnostics(SILFunction *fn, printActorIsolationForDiagnostics(fn, getActorIsolation(), os); return; case Task: + if (fn->isAsync() && fn->getASTContext().LangOpts.hasFeature( + Feature::NonisolatedNonsendingByDefault)) { + if (isNonisolatedNonsendingTaskIsolated()) { + os << "task-isolated"; + return; + } + os << "@concurrent task-isolated"; + return; + } + + if (isNonisolatedNonsendingTaskIsolated()) { + os << "nonisolated(nonsending) task-isolated"; + return; + } + os << "task-isolated"; return; } @@ -1636,8 +1674,13 @@ std::optional SILDynamicMergedIsolationInfo::merge(SILIsolationInfo other) const { // If we are greater than the other kind, then we are further along the // lattice. We ignore the change. - if (unsigned(innerInfo.getKind() > unsigned(other.getKind()))) + // + // NOTE: If we are further along, then we both cannot be task isolated. In + // such a case, we are the only potential thing that can be + // nonisolated(unsafe)... so we do not need to try to propagate. + if (unsigned(innerInfo.getKind() > unsigned(other.getKind()))) { return {*this}; + } // If we are both actor isolated... if (innerInfo.isActorIsolated() && other.isActorIsolated()) { @@ -1672,6 +1715,21 @@ SILDynamicMergedIsolationInfo::merge(SILIsolationInfo other) const { return {other.withUnsafeNonIsolated(false)}; } + // We know that we are either the same as other or other is further along. If + // other is further along, it is the only thing that can propagate the task + // isolated bit. So we do not need to do anything. If we are equal though, we + // may need to propagate the bit. This ensures that when we emit a diagnostic + // we appropriately say potentially actor isolated code instead of code in the + // current task. + // + // TODO: We should really represent this as a separate isolation info + // kind... but that would be a larger change than we want for 6.2. + if (innerInfo.isTaskIsolated() && other.isTaskIsolated()) { + if (innerInfo.isNonisolatedNonsendingTaskIsolated() || + other.isNonisolatedNonsendingTaskIsolated()) + return other.withNonisolatedNonsendingTaskIsolated(true); + } + // Otherwise, just return other. return {other}; } diff --git a/test/ClangImporter/regionbasedisolation.swift b/test/ClangImporter/regionbasedisolation.swift index 41b1fc3de29db..4f86aedd320a0 100644 --- a/test/ClangImporter/regionbasedisolation.swift +++ b/test/ClangImporter/regionbasedisolation.swift @@ -134,14 +134,15 @@ nonisolated(nonsending) func useValueNonIsolatedNonSending(_ t: T) async {} let x = ObjCObject() await x.useValue(y) await useValueConcurrently(x) // expected-error {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending main actor-isolated 'x' to nonisolated global function 'useValueConcurrently' risks causing data races between nonisolated and main actor-isolated uses}} + // expected-ni-note @-1 {{sending main actor-isolated 'x' to nonisolated global function 'useValueConcurrently' risks causing data races between nonisolated and main actor-isolated uses}} + // expected-ni-ns-note @-2 {{sending main actor-isolated 'x' to @concurrent global function 'useValueConcurrently' risks causing data races between @concurrent and main actor-isolated uses}} } func testTaskLocal(_ y: NSObject) async { let x = ObjCObject() await x.useValue(y) await useValueConcurrently(x) // expected-ni-ns-error {{sending 'x' risks causing data races}} - // expected-ni-ns-note @-1 {{sending task-isolated 'x' to nonisolated global function 'useValueConcurrently' risks causing data races between nonisolated and task-isolated uses}} + // expected-ni-ns-note @-1 {{sending task-isolated 'x' to @concurrent global function 'useValueConcurrently' risks causing data races between @concurrent and task-isolated uses}} // This is not safe since we merge x into y's region making x task // isolated. We then try to send it to a main actor function. diff --git a/test/Concurrency/nonisolated_inherits_isolation.swift b/test/Concurrency/nonisolated_inherits_isolation.swift index b12f2de7bc905..82dc816633761 100644 --- a/test/Concurrency/nonisolated_inherits_isolation.swift +++ b/test/Concurrency/nonisolated_inherits_isolation.swift @@ -289,13 +289,13 @@ func unspecifiedCallingVariousNonisolated(_ x: NonSendableKlass) async { await x.nonisolatedCaller() await x.nonisolatedNonSendingCaller() await x.concurrentCaller() // expected-enabled-error {{sending 'x' risks causing data races}} - // expected-enabled-note @-1 {{sending task-isolated 'x' to nonisolated instance method 'concurrentCaller()' risks causing data races between nonisolated and task-isolated uses}} + // expected-enabled-note @-1 {{sending task-isolated 'x' to @concurrent instance method 'concurrentCaller()' risks causing data races between @concurrent and task-isolated uses}} await unspecifiedAsyncUse(x) await nonisolatedAsyncUse(x) await nonisolatedNonSendingAsyncUse(x) await concurrentAsyncUse(x) // expected-enabled-error {{sending 'x' risks causing data races}} - // expected-enabled-note @-1 {{sending task-isolated 'x' to nonisolated global function 'concurrentAsyncUse' risks causing data races between nonisolated and task-isolated uses}} + // expected-enabled-note @-1 {{sending task-isolated 'x' to @concurrent global function 'concurrentAsyncUse' risks causing data races between @concurrent and task-isolated uses}} } nonisolated func nonisolatedCallingVariousNonisolated(_ x: NonSendableKlass) async { @@ -303,31 +303,33 @@ nonisolated func nonisolatedCallingVariousNonisolated(_ x: NonSendableKlass) asy await x.nonisolatedCaller() await x.nonisolatedNonSendingCaller() await x.concurrentCaller() // expected-enabled-error {{sending 'x' risks causing data races}} - // expected-enabled-note @-1 {{sending task-isolated 'x' to nonisolated instance method 'concurrentCaller()' risks causing data races between nonisolated and task-isolated uses}} + // expected-enabled-note @-1 {{sending task-isolated 'x' to @concurrent instance method 'concurrentCaller()' risks causing data races between @concurrent and task-isolated uses}} await unspecifiedAsyncUse(x) await nonisolatedAsyncUse(x) await nonisolatedNonSendingAsyncUse(x) await concurrentAsyncUse(x) // expected-enabled-error {{sending 'x' risks causing data races}} - // expected-enabled-note @-1 {{sending task-isolated 'x' to nonisolated global function 'concurrentAsyncUse' risks causing data races between nonisolated and task-isolated uses}} + // expected-enabled-note @-1 {{sending task-isolated 'x' to @concurrent global function 'concurrentAsyncUse' risks causing data races between @concurrent and task-isolated uses}} } nonisolated(nonsending) func nonisolatedNonSendingCallingVariousNonisolated(_ x: NonSendableKlass) async { await x.unspecifiedCaller() // expected-disabled-error {{sending 'x' risks causing data races}} - // expected-disabled-note @-1 {{sending task-isolated 'x' to nonisolated instance method 'unspecifiedCaller()' risks causing data races between nonisolated and task-isolated uses}} + // expected-disabled-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated instance method 'unspecifiedCaller()' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} await x.nonisolatedCaller() // expected-disabled-error {{sending 'x' risks causing data races}} - // expected-disabled-note @-1 {{sending task-isolated 'x' to nonisolated instance method 'nonisolatedCaller()' risks causing data races between nonisolated and task-isolated uses}} + // expected-disabled-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated instance method 'nonisolatedCaller()' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} await x.nonisolatedNonSendingCaller() await x.concurrentCaller() // expected-error {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending task-isolated 'x' to nonisolated instance method 'concurrentCaller()' risks causing data races between nonisolated and task-isolated uses}} + // expected-disabled-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated instance method 'concurrentCaller()' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} + // expected-enabled-note @-2 {{sending task-isolated 'x' to @concurrent instance method 'concurrentCaller()' risks causing data races between @concurrent and task-isolated uses}} await unspecifiedAsyncUse(x) // expected-disabled-error {{sending 'x' risks causing data races}} - // expected-disabled-note @-1 {{sending task-isolated 'x' to nonisolated global function 'unspecifiedAsyncUse' risks causing data races between nonisolated and task-isolated uses}} + // expected-disabled-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated global function 'unspecifiedAsyncUse' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} await nonisolatedAsyncUse(x) // expected-disabled-error {{sending 'x' risks causing data races}} - // expected-disabled-note @-1 {{sending task-isolated 'x' to nonisolated global function 'nonisolatedAsyncUse' risks causing data races between nonisolated and task-isolated uses}} + // expected-disabled-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated global function 'nonisolatedAsyncUse' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} await nonisolatedNonSendingAsyncUse(x) await concurrentAsyncUse(x) // expected-error {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending task-isolated 'x' to nonisolated global function 'concurrentAsyncUse' risks causing data races between nonisolated and task-isolated uses}} + // expected-disabled-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated global function 'concurrentAsyncUse' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} + // expected-enabled-note @-2 {{sending task-isolated 'x' to @concurrent global function 'concurrentAsyncUse' risks causing data races between @concurrent and task-isolated uses}} } @concurrent func concurrentCallingVariousNonisolated(_ x: NonSendableKlass) async { diff --git a/test/Concurrency/transfernonsendable.swift b/test/Concurrency/transfernonsendable.swift index 980677aecc880..755a37371d8f1 100644 --- a/test/Concurrency/transfernonsendable.swift +++ b/test/Concurrency/transfernonsendable.swift @@ -71,6 +71,7 @@ final class FinalMainActorIsolatedKlass { func useInOut(_ x: inout T) {} func useValue(_ x: T) {} func useValueAsync(_ x: T) async {} +@concurrent func useValueAsyncConcurrent(_ x: T) async {} @MainActor func transferToMain(_ t: T) async {} @@ -2074,3 +2075,10 @@ func inferLocationOfCapturedTaskIsolatedSelfCorrectly() { } } +nonisolated(nonsending) func testCallNonisolatedNonsending(_ x: NonSendableKlass) async { + await useValueAsync(x) // expected-tns-ni-warning {{sending 'x' risks causing data races}} + // expected-tns-ni-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} + await useValueAsyncConcurrent(x) // expected-tns-warning {{sending 'x' risks causing data races}} + // expected-tns-ni-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated global function 'useValueAsyncConcurrent' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} + // expected-tns-ni-ns-note @-2 {{sending task-isolated 'x' to @concurrent global function 'useValueAsyncConcurrent' risks causing data races between @concurrent and task-isolated uses}} +} diff --git a/test/Concurrency/transfernonsendable_asynclet.swift b/test/Concurrency/transfernonsendable_asynclet.swift index 8db02034ef315..f00bb44a5876b 100644 --- a/test/Concurrency/transfernonsendable_asynclet.swift +++ b/test/Concurrency/transfernonsendable_asynclet.swift @@ -1,5 +1,5 @@ -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -verify-additional-prefix ni- +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault -verify-additional-prefix ni-ns- // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability @@ -86,7 +86,8 @@ struct TwoFieldKlassBox { func asyncLet_Let_ActorIsolated_Simple1() async { let x = NonSendableKlass() async let y = transferToMainInt(x) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x) // expected-note {{access can happen concurrently}} let _ = await y } @@ -94,7 +95,8 @@ func asyncLet_Let_ActorIsolated_Simple1() async { func asyncLet_Let_ActorIsolated_Simple2() async { let x = NonSendableKlass() async let y = transferToMainInt(x) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} let _ = await y @@ -104,7 +106,8 @@ func asyncLet_Let_ActorIsolated_Simple2() async { func asyncLet_Let_ActorIsolated_Simple3() async { let x = NonSendableKlass() async let y = transferToMainInt(x) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} // TODO: We shouldn't emit the 2nd error here given the current implementation // since it is only accessible along the else path but we already hit @@ -122,7 +125,8 @@ func asyncLet_Let_ActorIsolated_Simple3() async { func asyncLet_Let_ActorIsolated_Simple4() async { let x = NonSendableKlass() async let y = transferToMainInt(x) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} if await booleanFlag { useValue(x) // expected-note {{access can happen concurrently}} @@ -135,7 +139,8 @@ func asyncLet_Let_ActorIsolated_Simple4() async { func asyncLet_Let_ActorIsolated_Simple5() async { let x = NonSendableKlass() async let y = transferToMainInt(x) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} if await booleanFlag { let _ = await y @@ -150,7 +155,8 @@ func asyncLet_Let_ActorIsolated_Simple5() async { func asyncLet_Let_ActorIsolated_AccessFieldsClass1() async { let x = NonSendableKlass() async let y = transferToMainInt(x.field) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x) // expected-note {{access can happen concurrently}} let _ = await y @@ -159,7 +165,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsClass1() async { func asyncLet_Let_ActorIsolated_AccessFieldsClass2() async { let x = NonSendableKlass() async let y = transferToMainInt(x.field) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.field) // expected-note {{access can happen concurrently}} let _ = await y @@ -168,7 +175,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsClass2() async { func asyncLet_Let_ActorIsolated_AccessFieldsClass3() async { let x = NonSendableKlass() async let y = transferToMainInt(x.field) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.field2) // expected-note {{access can happen concurrently}} let _ = await y @@ -179,7 +187,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsClass3() async { func asyncLet_Let_ActorIsolated_AccessFieldsStruct1() async { let x = TwoFieldKlassBox() async let y = transferToMainInt(x.k1) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x) // expected-note {{access can happen concurrently}} let _ = await y @@ -188,7 +197,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsStruct1() async { func asyncLet_Let_ActorIsolated_AccessFieldsStruct2() async { let x = TwoFieldKlassBox() async let y = transferToMainInt(x.k1) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.k1) // expected-note {{access can happen concurrently}} let _ = await y @@ -197,7 +207,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsStruct2() async { func asyncLet_Let_ActorIsolated_AccessFieldsStruct3() async { let x = TwoFieldKlassBox() async let y = transferToMainInt(x.k1) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.k2) // expected-note {{access can happen concurrently}} let _ = await y @@ -206,7 +217,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsStruct3() async { func asyncLet_Let_ActorIsolated_AccessFieldsStruct4() async { let x = TwoFieldKlassBox() async let y = transferToMainInt(x.k2.field2) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.k1.field) // expected-note {{access can happen concurrently}} let _ = await y @@ -217,7 +229,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsStruct4() async { func asyncLet_Let_ActorIsolated_AccessFieldsTuple1() async { let x = (TwoFieldKlassBox(), TwoFieldKlassBox()) async let y = transferToMainInt(x.0.k1) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x) // expected-note {{access can happen concurrently}} let _ = await y @@ -226,7 +239,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsTuple1() async { func asyncLet_Let_ActorIsolated_AccessFieldsTuple2() async { let x = (TwoFieldKlassBox(), TwoFieldKlassBox()) async let y = transferToMainInt(x.0.k1) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.1) // expected-note {{access can happen concurrently}} let _ = await y @@ -235,7 +249,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsTuple2() async { func asyncLet_Let_ActorIsolated_AccessFieldsTuple3() async { let x = (TwoFieldKlassBox(), TwoFieldKlassBox()) async let y = transferToMainInt(x.0.k1) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.1.k2) // expected-note {{access can happen concurrently}} let _ = await y @@ -244,7 +259,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsTuple3() async { func asyncLet_Let_ActorIsolated_AccessFieldsTuple4() async { let x = (TwoFieldKlassBox(), TwoFieldKlassBox()) async let y = transferToMainInt(x.1.k1.field2) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.0.k2.field) // expected-note {{access can happen concurrently}} let _ = await y @@ -255,9 +271,11 @@ func asyncLet_Let_ActorIsolated_CallBuriedInOtherExpr1() async { let x2 = NonSendableKlass() async let y = useValue(transferToMainInt(x) + transferToMainInt(x2)) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-warning @-2 {{sending 'x2' risks causing data races}} - // expected-note @-3 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-warning @-3 {{sending 'x2' risks causing data races}} + // expected-ni-note @-4 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-5 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x) // expected-note {{access can happen concurrently}} let _ = await y @@ -269,9 +287,11 @@ func asyncLet_Let_ActorIsolated_CallBuriedInOtherExpr2() async { let x2 = NonSendableKlass() async let y = useValue(transferToMainInt(x) + transferToMainInt(x2)) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-warning @-2 {{sending 'x2' risks causing data races}} - // expected-note @-3 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-warning @-3 {{sending 'x2' risks causing data races}} + // expected-ni-note @-4 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-5 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x2) // expected-note {{access can happen concurrently}} let _ = await y @@ -284,9 +304,11 @@ func asyncLet_Let_ActorIsolated_CallBuriedInOtherExpr3() async { let x2 = NonSendableKlass() async let y = useValue(transferToMainInt(x) + transferToMainInt(x2)) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-warning @-2 {{sending 'x2' risks causing data races}} - // expected-note @-3 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-warning @-3 {{sending 'x2' risks causing data races}} + // expected-ni-note @-4 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-5 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} // We only error on the first value captured if multiple values are captured // since we track a single partial_apply as a transfer instruction. @@ -300,8 +322,9 @@ func asyncLet_Let_ActorIsolated_CallBuriedInOtherExpr4() async { async let y = useValue(transferToMainInt(x) + transferToMainInt(x)) // expected-warning @-1:26 {{sending 'x' risks causing data races}} - // expected-note @-2:26 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-note @-3:49 {{access can happen concurrently}} + // expected-ni-note @-2:26 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-3:26 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-note @-4:49 {{access can happen concurrently}} let _ = await y } @@ -313,8 +336,9 @@ func asyncLet_Let_ActorIsolated_CallBuriedInOtherExpr5() async { async let y = useValue(transferToMainInt(x) + transferToCustomInt(x)) // expected-warning @-1 {{sending 'x' risks causing data races}} - // expected-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-note @-3:49 {{access can happen concurrently}} + // expected-ni-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-3 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-note @-4:49 {{access can happen concurrently}} let _ = await y } @@ -325,8 +349,9 @@ func asyncLet_Let_ActorIsolated_MultipleAsyncLet1() async { let x = NonSendableKlass() async let y = useValue(transferToMainInt(x)), z = useValue(transferToMainInt(x)) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-note @-2:53 {{access can happen concurrently}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-note @-3:53 {{access can happen concurrently}} let _ = await y let _ = await z @@ -349,7 +374,8 @@ func asyncLet_Let_ActorIsolated_MultipleAsyncLet3() async { async let y = useValue(transferToMainInt(x)), z = useValue(transferToMainInt(x2)) // expected-warning @-1 {{sending 'x2' risks causing data races}} - // expected-note @-2 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-2 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-3 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x2) // expected-note {{access can happen concurrently}} let _ = await y @@ -362,9 +388,11 @@ func asyncLet_Let_ActorIsolated_MultipleAsyncLet4() async { async let y = useValue(transferToMainInt(x)), z = useValue(transferToMainInt(x2)) // expected-warning @-1 {{sending 'x' risks causing data races}} - // expected-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-warning @-3 {{sending 'x2' risks causing data races}} - // expected-note @-4 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-3 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-warning @-4 {{sending 'x2' risks causing data races}} + // expected-ni-note @-5 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-6 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} let _ = await y let _ = await z @@ -378,9 +406,11 @@ func asyncLet_Let_ActorIsolated_MultipleAsyncLet5() async { async let y = useValue(transferToMainInt(x)), z = useValue(transferToMainInt(x2)) // expected-warning @-1 {{sending 'x' risks causing data races}} - // expected-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-warning @-3 {{sending 'x2' risks causing data races}} - // expected-note @-4 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-3 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-warning @-4 {{sending 'x2' risks causing data races}} + // expected-ni-note @-5 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-6 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} let _ = await y useValue(x) // expected-note {{access can happen concurrently}} @@ -394,9 +424,11 @@ func asyncLet_Let_ActorIsolated_MultipleAsyncLet6() async { async let y = useValue(transferToMainInt(x)), z = useValue(transferToMainInt(x2)) // expected-warning @-1 {{sending 'x' risks causing data races}} - // expected-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-warning @-3 {{sending 'x2' risks causing data races}} - // expected-note @-4 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-3 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-warning @-4 {{sending 'x2' risks causing data races}} + // expected-ni-note @-5 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-6 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} let _ = await y useValue(x) // expected-note {{access can happen concurrently}} @@ -724,7 +756,8 @@ func asyncLetWithoutCapture() async { // // NOTE: Error below will go away in next commit. async let x: NonSendableKlass = await returnValueFromMain() - // expected-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'returnValueFromMain()' to nonisolated context}} + // expected-ni-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'returnValueFromMain()' to nonisolated context}} + // expected-ni-ns-warning @-2 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'returnValueFromMain()' to @concurrent context}} let y = await x await transferToMain(y) // expected-warning {{sending 'y' risks causing data races}} // expected-note @-1 {{sending 'y' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}} @@ -736,7 +769,8 @@ func asyncLet_Let_ActorIsolated_Method() async { let a = MyActor() let x = NonSendableKlass() async let y = a.useKlass(x) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to actor-isolated instance method 'useKlass' risks causing data races between actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to actor-isolated instance method 'useKlass' risks causing data races between actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to actor-isolated instance method 'useKlass' risks causing data races between actor-isolated and local @concurrent uses}} useValue(x) // expected-note {{access can happen concurrently}} let _ = await y diff --git a/test/Concurrency/transfernonsendable_initializers.swift b/test/Concurrency/transfernonsendable_initializers.swift index ceef4f8745ab7..b298fadbb3835 100644 --- a/test/Concurrency/transfernonsendable_initializers.swift +++ b/test/Concurrency/transfernonsendable_initializers.swift @@ -1,5 +1,5 @@ -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null -enable-upcoming-feature NonisolatedNonsendingByDefault +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -swift-version 6 -verify -verify-additional-prefix ni- %s -o /dev/null +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -swift-version 6 -verify -verify-additional-prefix ni-ns- %s -o /dev/null -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: asserts @@ -36,7 +36,8 @@ actor ActorWithSynchronousNonIsolatedInit { // TODO: This should say actor isolated. let _ = { @MainActor in print(newK) // expected-error {{sending 'newK' risks causing data races}} - // expected-note @-1 {{task-isolated 'newK' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} + // expected-ni-note @-1 {{task-isolated 'newK' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} + // expected-ni-ns-note @-2 {{task-isolated 'newK' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} } } diff --git a/test/Concurrency/transfernonsendable_sending_results.swift b/test/Concurrency/transfernonsendable_sending_results.swift index 1921886ab5937..4ffacba9f1a6e 100644 --- a/test/Concurrency/transfernonsendable_sending_results.swift +++ b/test/Concurrency/transfernonsendable_sending_results.swift @@ -1,5 +1,5 @@ -// RUN: %target-swift-frontend -emit-sil -parse-as-library -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -// RUN: %target-swift-frontend -emit-sil -parse-as-library -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault +// RUN: %target-swift-frontend -emit-sil -parse-as-library -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -verify-additional-prefix ni- +// RUN: %target-swift-frontend -emit-sil -parse-as-library -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault -verify-additional-prefix ni-ns- // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability @@ -143,7 +143,8 @@ func transferInAndOut(_ x: sending NonSendableKlass) -> sending NonSendableKlass func transferReturnArg(_ x: NonSendableKlass) -> sending NonSendableKlass { return x // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{task-isolated 'x' cannot be a 'sending' result. task-isolated uses may race with caller uses}} + // expected-ni-note @-1 {{task-isolated 'x' cannot be a 'sending' result. task-isolated uses may race with caller uses}} + // expected-ni-ns-note @-2 {{task-isolated 'x' cannot be a 'sending' result. task-isolated uses may race with caller uses}} } // TODO: This will be fixed once I represent @MainActor on func types. @@ -240,7 +241,8 @@ func asyncLetReabstractionThunkTest() async { func asyncLetReabstractionThunkTest2() async { // We emit the error here since we are returning a main actor isolated value. async let newValue: NonSendableKlass = await getMainActorValueAsync() - // expected-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'getMainActorValueAsync()' to nonisolated context}} + // expected-ni-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'getMainActorValueAsync()' to nonisolated context}} + // expected-ni-ns-warning @-2 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'getMainActorValueAsync()' to @concurrent context}} let _ = await newValue @@ -263,7 +265,8 @@ func asyncLetReabstractionThunkTest2() async { @MainActor func asyncLetReabstractionThunkTestGlobalActor2() async { // We emit the error here since we are returning a main actor isolated value. async let newValue: NonSendableKlass = await getMainActorValueAsync() - // expected-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'getMainActorValueAsync()' to nonisolated context}} + // expected-ni-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'getMainActorValueAsync()' to nonisolated context}} + // expected-ni-ns-warning @-2 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'getMainActorValueAsync()' to @concurrent context}} let _ = await newValue diff --git a/test/Serialization/caller_isolation_inherit.swift b/test/Serialization/caller_isolation_inherit.swift index a6d3b23442998..632d746f549ae 100644 --- a/test/Serialization/caller_isolation_inherit.swift +++ b/test/Serialization/caller_isolation_inherit.swift @@ -32,7 +32,7 @@ actor A { func test1a() async { await WithFeature.unspecifiedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated global function 'unspecifiedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent global function 'unspecifiedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // unspecifiedAsyncCaller(_:) @@ -48,7 +48,7 @@ actor A { func test2() async { await WithoutFeature.unspecifiedAsync(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated global function 'unspecifiedAsync' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent global function 'unspecifiedAsync' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // unspecifiedAsyncConcurrent(_:) @@ -59,7 +59,7 @@ actor A { // an error. await WithoutFeature.unspecifiedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated global function 'unspecifiedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent global function 'unspecifiedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // unspecifiedAsyncCaller(_:) @@ -82,7 +82,7 @@ actor A { func test3a() async { await WithFeature.nonisolatedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated global function 'nonisolatedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent global function 'nonisolatedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // nonisolatedAsyncCaller(_:) @@ -98,7 +98,7 @@ actor A { func test4() async { await WithoutFeature.nonisolatedAsync(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated global function 'nonisolatedAsync' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent global function 'nonisolatedAsync' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // nonisolatedAsyncConcurrent(_:) @@ -107,7 +107,7 @@ actor A { func test4a() async { await WithoutFeature.nonisolatedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated global function 'nonisolatedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent global function 'nonisolatedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // nonisolatedAsyncCaller(_:) @@ -132,7 +132,7 @@ actor A { let s = WithFeature.S() await s.unspecifiedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated instance method 'unspecifiedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent instance method 'unspecifiedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // S.unspecifiedAsyncCaller(_:) @@ -158,7 +158,7 @@ actor A { let s = WithFeature.S() await s.nonisolatedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated instance method 'nonisolatedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent instance method 'nonisolatedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // S.nonisolatedAsyncCaller(_:) @@ -176,7 +176,7 @@ actor A { let s = WithoutFeature.S() await s.unspecifiedAsync(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated instance method 'unspecifiedAsync' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent instance method 'unspecifiedAsync' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // S.unspecifiedAsyncConcurrent(_:) @@ -186,7 +186,7 @@ actor A { let s = WithoutFeature.S() await s.unspecifiedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated instance method 'unspecifiedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent instance method 'unspecifiedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // S.unspecifiedAsyncCaller(_:) @@ -204,7 +204,7 @@ actor A { let s = WithoutFeature.S() await s.nonisolatedAsync(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated instance method 'nonisolatedAsync' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent instance method 'nonisolatedAsync' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // S.nonisolatedAsyncConcurrent(_:) @@ -214,7 +214,7 @@ actor A { let s = WithoutFeature.S() await s.nonisolatedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated instance method 'nonisolatedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent instance method 'nonisolatedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // S.nonisolatedAsyncCaller(_:) From f920aba2f9c405922728ca883fae25f6583fe383 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 2 Jul 2025 16:11:43 -0700 Subject: [PATCH 07/10] [rbi] Use interned StringRefs for diagnostics instead of SmallString<64>. This makes the code easier to write and also prevents any lifetime issues from a diagnostic outliving the SmallString due to diagnostic transactions. (cherry picked from commit 010fa39f31e051a33e2b511261cd057cc0052141) --- include/swift/AST/DiagnosticsSIL.def | 34 +- include/swift/AST/Identifier.h | 2 +- .../SILOptimizer/Utils/SILIsolationInfo.h | 22 ++ .../Mandatory/SendNonSendable.cpp | 359 ++++++------------ lib/SILOptimizer/Utils/SILIsolationInfo.cpp | 33 ++ 5 files changed, 181 insertions(+), 269 deletions(-) diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 6c135b3619cd2..943e67e29be8f 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -990,11 +990,11 @@ NOTE(regionbasedisolation_type_use_after_send_callee, none, (Type, StringRef, const ValueDecl *, StringRef)) NOTE(regionbasedisolation_named_info_send_yields_race, none, - "sending %1%0 to %2 callee risks causing data races between %2 and local %3 uses", - (Identifier, StringRef, StringRef, StringRef)) + "sending %select{%2 |}0%1 to %3 callee risks causing data races between %3 and local %4 uses", + (bool, Identifier, StringRef, StringRef, StringRef)) NOTE(regionbasedisolation_named_info_send_yields_race_callee, none, - "sending %1%0 to %2 %kind3 risks causing data races between %2 and local %4 uses", - (Identifier, StringRef, StringRef, const ValueDecl *, StringRef)) + "sending %select{%2 |}0%1 to %3 %kind4 risks causing data races between %3 and local %5 uses", + (bool, Identifier, StringRef, StringRef, const ValueDecl *, StringRef)) // Use after send closure. NOTE(regionbasedisolation_type_isolated_capture_yields_race, none, @@ -1010,8 +1010,8 @@ NOTE(regionbasedisolation_named_value_used_after_explicit_sending, none, "%0 used after being passed as a 'sending' parameter; Later uses could race", (Identifier)) NOTE(regionbasedisolation_named_isolated_closure_yields_race, none, - "%0%1 is captured by a %2 closure. %2 uses in closure may race against later %3 uses", - (StringRef, Identifier, StringRef, StringRef)) + "%select{%1 |}0%2 is captured by a %3 closure. %3 uses in closure may race against later %4 uses", + (bool, StringRef, Identifier, StringRef, StringRef)) NOTE(regionbasedisolation_typed_use_after_sending, none, "Passing value of non-Sendable type %0 as a 'sending' argument risks causing races in between local and caller code", @@ -1024,19 +1024,19 @@ NOTE(regionbasedisolation_typed_use_after_sending_callee, none, // Sending Never Sendable Emitter NOTE(regionbasedisolation_named_send_never_sendable, none, - "sending %1%0 to %2 callee risks causing data races between %2 and %3 uses", - (Identifier, StringRef, StringRef, StringRef)) + "sending %select{%2 |}0%1 to %3 callee risks causing data races between %3 and %4 uses", + (bool, Identifier, StringRef, StringRef, StringRef)) NOTE(regionbasedisolation_named_send_never_sendable_callee, none, - "sending %1%0 to %2 %kind3 risks causing data races between %2 and %4 uses", - (Identifier, StringRef, StringRef, const ValueDecl *, StringRef)) + "sending %select{%2 |}0%1 to %3 %kind4 risks causing data races between %3 and %5 uses", + (bool, Identifier, StringRef, StringRef, const ValueDecl *, StringRef)) NOTE(regionbasedisolation_named_send_into_sending_param, none, - "%0%1 is passed as a 'sending' parameter; Uses in callee may race with " - "later %0uses", - (StringRef, Identifier)) + "%select{%1 |}0%2 is passed as a 'sending' parameter; Uses in callee may race with " + "later %1 uses", + (bool, StringRef, Identifier)) NOTE(regionbasedisolation_named_nosend_send_into_result, none, - "%0%1 cannot be a 'sending' result. %2 uses may race with caller uses", - (StringRef, Identifier, StringRef)) + "%select{%1 |}0%2 cannot be a 'sending' result. %3 uses may race with caller uses", + (bool, StringRef, Identifier, StringRef)) NOTE(regionbasedisolation_typed_tns_passed_to_sending, none, "Passing %0 value of non-Sendable type %1 as a 'sending' parameter risks " "causing races inbetween %0 uses and uses reachable from the callee", @@ -1098,10 +1098,10 @@ NOTE(regionbasedisolation_inout_sending_must_be_reinitialized, none, "'inout sending' parameter must be reinitialized before function exit with a non-actor isolated value", ()) ERROR(regionbasedisolation_inout_sending_cannot_be_actor_isolated, none, - "'inout sending' parameter %0 cannot be %1at end of function", + "'inout sending' parameter %0 cannot be %1 at end of function", (Identifier, StringRef)) NOTE(regionbasedisolation_inout_sending_cannot_be_actor_isolated_note, none, - "%1%0 risks causing races in between %1uses and caller uses since caller assumes value is not actor isolated", + "%1 %0 risks causing races in between %1 uses and caller uses since caller assumes value is not actor isolated", (Identifier, StringRef)) //=== diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h index 4724b5b202e3c..ee6a4c0a8b8d8 100644 --- a/include/swift/AST/Identifier.h +++ b/include/swift/AST/Identifier.h @@ -230,7 +230,7 @@ class Identifier { private: bool isOperatorSlow() const; }; - + class DeclName; class DeclNameRef; class ObjCSelector; diff --git a/include/swift/SILOptimizer/Utils/SILIsolationInfo.h b/include/swift/SILOptimizer/Utils/SILIsolationInfo.h index c7bc151a7635d..a57a50c9a950a 100644 --- a/include/swift/SILOptimizer/Utils/SILIsolationInfo.h +++ b/include/swift/SILOptimizer/Utils/SILIsolationInfo.h @@ -380,8 +380,16 @@ class SILIsolationInfo { /// form of diagnostic than other cases. void printForCodeDiagnostic(SILFunction *fn, llvm::raw_ostream &os) const; + /// Overload of printForCodeDiagnostics that returns an interned StringRef + /// owned by the AST. + StringRef printForCodeDiagnostic(SILFunction *fn) const; + void printForDiagnostics(SILFunction *fn, llvm::raw_ostream &os) const; + /// Overload of printForDiagnostics that returns an interned StringRef owned + /// by the AST. + StringRef printForDiagnostics(SILFunction *fn) const; + SWIFT_DEBUG_DUMPER(dumpForDiagnostics(SILFunction *fn)) { printForDiagnostics(fn, llvm::dbgs()); llvm::dbgs() << '\n'; @@ -579,6 +587,12 @@ class SILIsolationInfo { SILFunction *fn, ActorIsolation iso, llvm::raw_ostream &os, StringRef openingQuotationMark = "'", bool asNoun = false); + /// Overload for printActorIsolationForDiagnostics that produces a StringRef. + static StringRef + printActorIsolationForDiagnostics(SILFunction *fn, ActorIsolation iso, + StringRef openingQuotationMark = "'", + bool asNoun = false); + void Profile(llvm::FoldingSetNodeID &id) const; private: @@ -648,6 +662,10 @@ class SILDynamicMergedIsolationInfo { innerInfo.printForDiagnostics(fn, os); } + StringRef printForDiagnostics(SILFunction *fn) const { + return innerInfo.printForDiagnostics(fn); + } + SWIFT_DEBUG_DUMPER(dumpForDiagnostics(SILFunction *fn)) { innerInfo.dumpForDiagnostics(fn); } @@ -656,6 +674,10 @@ class SILDynamicMergedIsolationInfo { innerInfo.printForCodeDiagnostic(fn, os); } + StringRef printForCodeDiagnostic(SILFunction *fn) const { + return innerInfo.printForCodeDiagnostic(fn); + } + void printForOneLineLogging(SILFunction *fn, llvm::raw_ostream &os) const { innerInfo.printForOneLineLogging(fn, os); } diff --git a/lib/SILOptimizer/Mandatory/SendNonSendable.cpp b/lib/SILOptimizer/Mandatory/SendNonSendable.cpp index f9e000064ef35..1f1fdf9e1a253 100644 --- a/lib/SILOptimizer/Mandatory/SendNonSendable.cpp +++ b/lib/SILOptimizer/Mandatory/SendNonSendable.cpp @@ -686,37 +686,24 @@ class UseAfterSendDiagnosticEmitter { .limitBehaviorIf(getBehaviorLimit()); // Then emit the note with greater context. - SmallString<64> descriptiveKindStr; - { - if (!namedValuesIsolationInfo.isDisconnected()) { - llvm::raw_svector_ostream os(descriptiveKindStr); - namedValuesIsolationInfo.printForDiagnostics(getFunction(), os); - os << ' '; - } - } - - SmallString<64> calleeIsolationStr; - { - llvm::raw_svector_ostream os(calleeIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), isolationCrossing.getCalleeIsolation(), os); - } - - SmallString<64> callerIsolationStr; - { - llvm::raw_svector_ostream os(callerIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), isolationCrossing.getCallerIsolation(), os); - } - + auto descriptiveKindStr = + namedValuesIsolationInfo.printForDiagnostics(getFunction()); + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCalleeIsolation()); + auto callerIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCallerIsolation()); + + bool isDisconnected = namedValuesIsolationInfo.isDisconnected(); if (auto callee = getSendingCallee()) { diagnoseNote( loc, diag::regionbasedisolation_named_info_send_yields_race_callee, - name, descriptiveKindStr, calleeIsolationStr, callee.value(), - callerIsolationStr); + isDisconnected, name, descriptiveKindStr, calleeIsolationStr, + callee.value(), callerIsolationStr); } else { diagnoseNote(loc, diag::regionbasedisolation_named_info_send_yields_race, - name, descriptiveKindStr, calleeIsolationStr, + isDisconnected, name, descriptiveKindStr, calleeIsolationStr, callerIsolationStr); } emitRequireInstDiagnostics(); @@ -733,33 +720,20 @@ class UseAfterSendDiagnosticEmitter { .limitBehaviorIf(getBehaviorLimit()); // Then emit the note with greater context. - SmallString<64> descriptiveKindStr; - { - if (!namedValuesIsolationInfo.isDisconnected()) { - llvm::raw_svector_ostream os(descriptiveKindStr); - namedValuesIsolationInfo.printForDiagnostics(getFunction(), os); - os << ' '; - } - } - - SmallString<64> calleeIsolationStr; - { - llvm::raw_svector_ostream os(calleeIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), isolationCrossing.getCalleeIsolation(), os); - } - - SmallString<64> callerIsolationStr; - { - llvm::raw_svector_ostream os(callerIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), isolationCrossing.getCallerIsolation(), os); - } + auto descriptiveKindStr = + namedValuesIsolationInfo.printForDiagnostics(getFunction()); + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCalleeIsolation()); + auto callerIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCallerIsolation()); + bool isDisconnected = namedValuesIsolationInfo.isDisconnected(); diagnoseNote(loc, diag::regionbasedisolation_named_info_send_yields_race_callee, - name, descriptiveKindStr, calleeIsolationStr, callee, - callerIsolationStr); + isDisconnected, name, descriptiveKindStr, calleeIsolationStr, + callee, callerIsolationStr); emitRequireInstDiagnostics(); } @@ -782,19 +756,12 @@ class UseAfterSendDiagnosticEmitter { .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); - SmallString<64> calleeIsolationStr; - { - llvm::raw_svector_ostream os(calleeIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), isolationCrossing.getCalleeIsolation(), os); - } - - SmallString<64> callerIsolationStr; - { - llvm::raw_svector_ostream os(callerIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), isolationCrossing.getCallerIsolation(), os); - } + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCalleeIsolation()); + auto callerIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCallerIsolation()); if (auto callee = getSendingCallee()) { diagnoseNote(loc, diag::regionbasedisolation_type_use_after_send_callee, @@ -848,32 +815,19 @@ class UseAfterSendDiagnosticEmitter { .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); - SmallString<64> descriptiveKindStr; - { - if (!namedValuesIsolationInfo.isDisconnected()) { - llvm::raw_svector_ostream os(descriptiveKindStr); - namedValuesIsolationInfo.printForDiagnostics(getFunction(), os); - os << ' '; - } - } - - SmallString<64> calleeIsolationStr; - { - llvm::raw_svector_ostream os(calleeIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), isolationCrossing.getCalleeIsolation(), os); - } - - SmallString<64> callerIsolationStr; - { - llvm::raw_svector_ostream os(callerIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), isolationCrossing.getCallerIsolation(), os); - } - - diagnoseNote( - loc, diag::regionbasedisolation_named_isolated_closure_yields_race, - descriptiveKindStr, name, calleeIsolationStr, callerIsolationStr) + auto descriptiveKindStr = + namedValuesIsolationInfo.printForDiagnostics(getFunction()); + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCalleeIsolation()); + auto callerIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCallerIsolation()); + bool isDisconnected = namedValuesIsolationInfo.isDisconnected(); + diagnoseNote(loc, + diag::regionbasedisolation_named_isolated_closure_yields_race, + isDisconnected, descriptiveKindStr, name, calleeIsolationStr, + callerIsolationStr) .highlight(loc.getSourceRange()); emitRequireInstDiagnostics(); } @@ -886,19 +840,12 @@ class UseAfterSendDiagnosticEmitter { .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); - SmallString<64> calleeIsolationStr; - { - llvm::raw_svector_ostream os(calleeIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), isolationCrossing.getCalleeIsolation(), os); - } - - SmallString<64> callerIsolationStr; - { - llvm::raw_svector_ostream os(callerIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), isolationCrossing.getCallerIsolation(), os); - } + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCalleeIsolation()); + auto callerIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCallerIsolation()); diagnoseNote(loc, diag::regionbasedisolation_type_isolated_capture_yields_race, @@ -1438,18 +1385,11 @@ class SendNeverSentDiagnosticEmitter { .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(getFunction(), os); - } - - SmallString<64> calleeIsolationStr; - { - llvm::raw_svector_ostream os(calleeIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), crossing.getCalleeIsolation(), os); - } + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), crossing.getCalleeIsolation()); if (auto callee = getSendingCallee()) { diagnoseNote( @@ -1466,32 +1406,20 @@ class SendNeverSentDiagnosticEmitter { void emitNamedFunctionArgumentClosure(SILLocation loc, Identifier name, ApplyIsolationCrossing crossing) { emitNamedOnlyError(loc, name); - SmallString<64> descriptiveKindStr; - { - if (!getIsolationRegionInfo().isDisconnected()) { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(getFunction(), os); - os << ' '; - } - } - SmallString<64> calleeIsolationStr; - { - llvm::raw_svector_ostream os(calleeIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), crossing.getCalleeIsolation(), os); - } - - SmallString<64> callerIsolationStr; - { - llvm::raw_svector_ostream os(callerIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), crossing.getCallerIsolation(), os); - } - - diagnoseNote( - loc, diag::regionbasedisolation_named_isolated_closure_yields_race, - descriptiveKindStr, name, calleeIsolationStr, callerIsolationStr) + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), crossing.getCalleeIsolation()); + auto callerIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), crossing.getCallerIsolation()); + bool isDisconnected = getIsolationRegionInfo().isDisconnected(); + diagnoseNote(loc, + diag::regionbasedisolation_named_isolated_closure_yields_race, + isDisconnected, descriptiveKindStr, name, calleeIsolationStr, + callerIsolationStr) .highlight(loc.getSourceRange()); } @@ -1502,11 +1430,8 @@ class SendNeverSentDiagnosticEmitter { .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(getFunction(), os); - } + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); if (auto callee = getSendingCallee()) { diagnoseNote( @@ -1524,12 +1449,8 @@ class SendNeverSentDiagnosticEmitter { void emitClosureErrorWithCapturedActor(Operand *partialApplyOp, Operand *actualUse, SILArgument *fArg) { - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().getIsolationInfo().printForCodeDiagnostic( - getFunction(), os); - } + auto descriptiveKindStr = + getIsolationRegionInfo().printForCodeDiagnostic(getFunction()); diagnoseError(partialApplyOp, diag::regionbasedisolation_typed_tns_passed_sending_closure, @@ -1537,12 +1458,8 @@ class SendNeverSentDiagnosticEmitter { .limitBehaviorIf(getDiagnosticBehaviorLimitForOperands( actualUse->getFunction(), {actualUse})); - descriptiveKindStr.clear(); - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().getIsolationInfo().printForDiagnostics( - getFunction(), os); - } + descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); diagnoseNote(actualUse, diag::regionbasedisolation_closure_captures_actor, fArg->getDecl()->getName(), descriptiveKindStr); } @@ -1557,12 +1474,8 @@ class SendNeverSentDiagnosticEmitter { void emitSendingClosureParamDirectlyIsolated(Operand *partialApplyOp, Operand *actualUse, SILArgument *fArg) { - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().getIsolationInfo().printForCodeDiagnostic( - getFunction(), os); - } + auto descriptiveKindStr = + getIsolationRegionInfo().printForCodeDiagnostic(getFunction()); diagnoseError(partialApplyOp, diag::regionbasedisolation_typed_tns_passed_sending_closure, @@ -1586,11 +1499,8 @@ class SendNeverSentDiagnosticEmitter { return; } - descriptiveKindStr.clear(); - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(getFunction(), os); - } + descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); auto diag = diag:: regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value; @@ -1607,11 +1517,8 @@ class SendNeverSentDiagnosticEmitter { return; } - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo()->printForCodeDiagnostic(getFunction(), os); - } + auto descriptiveKindStr = + getIsolationRegionInfo()->printForCodeDiagnostic(getFunction()); auto emitMainError = [&] { auto behaviorLimit = getDiagnosticBehaviorLimitForOperands( @@ -1643,11 +1550,8 @@ class SendNeverSentDiagnosticEmitter { } emitMainError(); - descriptiveKindStr.clear(); - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(getFunction(), os); - } + descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); auto diag = diag:: regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value_region; diagnoseNote(actualUseInfo->first, diag, descriptiveKindStr, @@ -1688,11 +1592,8 @@ class SendNeverSentDiagnosticEmitter { "Should never be disconnected?!"); emitNamedOnlyError(loc, name); - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(getFunction(), os); - } + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); diagnoseNote(loc, diag::regionbasedisolation_named_send_nt_asynclet_capture, name, descriptiveKindStr); @@ -1701,34 +1602,22 @@ class SendNeverSentDiagnosticEmitter { void emitNamedIsolation(SILLocation loc, Identifier name, ApplyIsolationCrossing isolationCrossing) { emitNamedOnlyError(loc, name); - SmallString<64> descriptiveKindStr; - SmallString<64> descriptiveKindStrWithSpace; - { - if (!getIsolationRegionInfo().isDisconnected()) { - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(getFunction(), os); - } - descriptiveKindStrWithSpace = descriptiveKindStr; - descriptiveKindStrWithSpace.push_back(' '); - } - } - SmallString<64> calleeIsolationStr; - { - llvm::raw_svector_ostream os(calleeIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), isolationCrossing.getCalleeIsolation(), os); - } + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCalleeIsolation()); + bool isDisconnected = getIsolationRegionInfo().isDisconnected(); if (auto callee = getSendingCallee()) { diagnoseNote(loc, diag::regionbasedisolation_named_send_never_sendable_callee, - name, descriptiveKindStrWithSpace, calleeIsolationStr, + isDisconnected, name, descriptiveKindStr, calleeIsolationStr, callee.value(), descriptiveKindStr); } else { diagnoseNote(loc, diag::regionbasedisolation_named_send_never_sendable, - name, descriptiveKindStrWithSpace, calleeIsolationStr, + isDisconnected, name, descriptiveKindStr, calleeIsolationStr, descriptiveKindStr); } } @@ -1736,34 +1625,21 @@ class SendNeverSentDiagnosticEmitter { void emitNamedSendingNeverSendableToSendingParam(SILLocation loc, Identifier varName) { emitNamedOnlyError(loc, varName); - SmallString<64> descriptiveKindStr; - { - if (!getIsolationRegionInfo().isDisconnected()) { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(getFunction(), os); - os << ' '; - } - } + + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); + bool isDisconnected = getIsolationRegionInfo().isDisconnected(); auto diag = diag::regionbasedisolation_named_send_into_sending_param; - diagnoseNote(loc, diag, descriptiveKindStr, varName); + diagnoseNote(loc, diag, isDisconnected, descriptiveKindStr, varName); } void emitNamedSendingReturn(SILLocation loc, Identifier varName) { emitNamedOnlyError(loc, varName); - SmallString<64> descriptiveKindStr; - SmallString<64> descriptiveKindStrWithSpace; - { - if (!getIsolationRegionInfo().isDisconnected()) { - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(getFunction(), os); - } - descriptiveKindStrWithSpace = descriptiveKindStr; - descriptiveKindStrWithSpace.push_back(' '); - } - } + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); + bool isDisconnected = getIsolationRegionInfo().isDisconnected(); auto diag = diag::regionbasedisolation_named_nosend_send_into_result; - diagnoseNote(loc, diag, descriptiveKindStrWithSpace, varName, + diagnoseNote(loc, diag, isDisconnected, descriptiveKindStr, varName, descriptiveKindStr); } @@ -2078,7 +1954,6 @@ bool SentNeverSendableDiagnosticInferrer::run() { return true; // See if we can infer a name from the value. - SmallString<64> resultingName; if (auto varName = inferNameHelper(op->get())) { diagnosticEmitter.emitNamedSendingNeverSendableToSendingParam( loc, *varName); @@ -2119,7 +1994,6 @@ bool SentNeverSendableDiagnosticInferrer::run() { } // See if we can infer a name from the value. - SmallString<64> resultingName; if (auto name = inferNameHelper(op->get())) { diagnosticEmitter.emitNamedIsolation(loc, *name, *isolation); return true; @@ -2167,7 +2041,6 @@ bool SentNeverSendableDiagnosticInferrer::run() { }) && "All result info must be the same... if that changes... update " "this code!"); - SmallString<64> resultingName; if (auto name = inferNameHelper(op->get())) { diagnosticEmitter.emitNamedSendingReturn(loc, *name); return true; @@ -2316,12 +2189,8 @@ void InOutSendingNotDisconnectedDiagnosticEmitter::emit() { } // Then emit the note with greater context. - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - actorIsolatedRegionInfo.printForDiagnostics(getFunction(), os); - os << ' '; - } + auto descriptiveKindStr = + actorIsolatedRegionInfo.printForDiagnostics(getFunction()); diagnoseError( functionExitingInst, @@ -2476,11 +2345,8 @@ static SILValue findOutParameter(SILValue v) { void AssignIsolatedIntoSendingResultDiagnosticEmitter::emit() { // Then emit the note with greater context. - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - isolatedValueIsolationRegionInfo.printForDiagnostics(getFunction(), os); - } + auto descriptiveKindStr = + isolatedValueIsolationRegionInfo.printForDiagnostics(getFunction()); // Grab the var name if we can find it. if (auto varName = VariableNameInferrer::inferName(srcOperand->get())) { @@ -2724,19 +2590,10 @@ void NonSendableIsolationCrossingResultDiagnosticEmitter::emit() { if (!isolationCrossing) return emitUnknownPatternError(); - SmallString<64> calleeIsolationStr; - { - llvm::raw_svector_ostream os(calleeIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), isolationCrossing->getCalleeIsolation(), os); - } - - SmallString<64> callerIsolationStr; - { - llvm::raw_svector_ostream os(callerIsolationStr); - SILIsolationInfo::printActorIsolationForDiagnostics( - getFunction(), isolationCrossing->getCallerIsolation(), os); - } + auto calleeIsolationStr = SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing->getCalleeIsolation()); + auto callerIsolationStr = SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing->getCallerIsolation()); auto type = getType(); if (getCalledDecl()) { diff --git a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp index 2a08f166c0cce..b4af1a75e28fc 100644 --- a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp +++ b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp @@ -1244,6 +1244,19 @@ void SILIsolationInfo::printOptions(llvm::raw_ostream &os) const { llvm::interleave(data, os, ", "); } +StringRef SILIsolationInfo::printActorIsolationForDiagnostics( + SILFunction *fn, ActorIsolation iso, StringRef openingQuotationMark, + bool asNoun) { + SmallString<64> string; + { + llvm::raw_svector_ostream os(string); + printActorIsolationForDiagnostics(fn, iso, os, openingQuotationMark, + asNoun); + } + + return fn->getASTContext().getIdentifier(string).str(); +} + void SILIsolationInfo::printActorIsolationForDiagnostics( SILFunction *fn, ActorIsolation iso, llvm::raw_ostream &os, StringRef openingQuotationMark, bool asNoun) { @@ -1400,6 +1413,16 @@ void SILIsolationInfo::Profile(llvm::FoldingSetNodeID &id) const { } } +StringRef SILIsolationInfo::printForDiagnostics(SILFunction *fn) const { + SmallString<64> string; + { + llvm::raw_svector_ostream os(string); + printForDiagnostics(fn, os); + } + + return fn->getASTContext().getIdentifier(string).str(); +} + void SILIsolationInfo::printForDiagnostics(SILFunction *fn, llvm::raw_ostream &os) const { switch (Kind(*this)) { @@ -1459,6 +1482,16 @@ void SILIsolationInfo::printForDiagnostics(SILFunction *fn, } } +StringRef SILIsolationInfo::printForCodeDiagnostic(SILFunction *fn) const { + SmallString<64> string; + { + llvm::raw_svector_ostream os(string); + printForCodeDiagnostic(fn, os); + } + + return fn->getASTContext().getIdentifier(string).str(); +} + void SILIsolationInfo::printForCodeDiagnostic(SILFunction *fn, llvm::raw_ostream &os) const { switch (Kind(*this)) { From 731d605950e6fd2b7aa486c8784d245b21d3be9c Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 7 Jul 2025 10:41:48 -0700 Subject: [PATCH 08/10] Update two tests for 4c1440735b8066d061c668d3b655955c1831f1dd. I cherry-picked 4c1440735b8066d061c668d3b655955c1831f1dd to prevent merge conflicts. I think these tests were updated by a subsequent PR. Rather than cherry-picking more work, I just updated these tests since the change seemed benign and that this kept the overall amount of cherry-picked commits small (converting %$NUMBER to %kind$NUMBER for some ValueDecls). --- test/SILOptimizer/missing_returns.swift | 40 ++++++++++++------------- test/SILOptimizer/return.swift | 4 +-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/test/SILOptimizer/missing_returns.swift b/test/SILOptimizer/missing_returns.swift index e6bb0299c779c..986a46567115c 100644 --- a/test/SILOptimizer/missing_returns.swift +++ b/test/SILOptimizer/missing_returns.swift @@ -10,29 +10,29 @@ struct MissingGetterSubscript1 { subscript (i : Int) -> Int { - } // expected-error {{missing return in getter expected to return 'Int'}} + } // expected-error {{missing return in getter for subscript expected to return 'Int'}} } // MARK: `decl/var/properties` struct X {} -var x13: X {} // expected-error {{missing return in getter expected to return 'X'}} +var x13: X {} // expected-error {{missing return in getter for var expected to return 'X'}} struct X14 {} extension X14 { var x14: X { - } // expected-error {{missing return in getter expected to return 'X'}} + } // expected-error {{missing return in getter for property expected to return 'X'}} } // https://github.com/apple/swift/issues/57936 enum E1_57936 { - var foo: Int {} // expected-error{{missing return in getter expected to return 'Int'}} + var foo: Int {} // expected-error{{missing return in getter for property expected to return 'Int'}} } enum E2_57936 { - var foo: T {} // expected-error{{missing return in getter expected to return 'T'}} + var foo: T {} // expected-error{{missing return in getter for property expected to return 'T'}} } // MARK: `decl/var/result_builders` @@ -51,7 +51,7 @@ var fv_nop: () { } var fv_missing: String { -} // expected-error {{missing return in getter expected to return 'String'}} +} // expected-error {{missing return in getter for var expected to return 'String'}} enum S_nop { subscript() -> () { @@ -60,30 +60,30 @@ enum S_nop { enum S_missing { subscript() -> String { - } // expected-error {{missing return in getter expected to return 'String'}} + } // expected-error {{missing return in getter for subscript expected to return 'String'}} } // MARK: `Sema/generic-subscript` struct S_generic_subscript_missing_return { subscript(x: Int) -> Value { - } // expected-error {{missing return in getter expected to return 'Value'}} + } // expected-error {{missing return in getter for subscript expected to return 'Value'}} } // MARK: New Test Cases enum MyEmptyType {} extension MyEmptyType { - var i: Int {} // expected-error{{missing return in getter expected to return 'Int'}} - var n: MyEmptyType {} // expected-error{{getter with uninhabited return type 'MyEmptyType' is missing call to another never-returning function on all paths}} + var i: Int {} // expected-error{{missing return in getter for property expected to return 'Int'}} + var n: MyEmptyType {} // expected-error{{getter for property with uninhabited return type 'MyEmptyType' is missing call to another never-returning function on all paths}} static subscript(root: MyEmptyType) -> A {} subscript(_ e: MyEmptyType) -> Int {} subscript(_ e: MyEmptyType) -> T {} - subscript(_ i: Int) -> Int {} // expected-error{{missing return in getter expected to return 'Int'}} - subscript(_ p: Int) -> T {} // expected-error{{missing return in getter expected to return 'T'}} - subscript(_ i: Int) -> Self {} // expected-error{{getter with uninhabited return type 'MyEmptyType' is missing call to another never-returning function on all paths}} + subscript(_ i: Int) -> Int {} // expected-error{{missing return in getter for subscript expected to return 'Int'}} + subscript(_ p: Int) -> T {} // expected-error{{missing return in getter for subscript expected to return 'T'}} + subscript(_ i: Int) -> Self {} // expected-error{{getter for subscript with uninhabited return type 'MyEmptyType' is missing call to another never-returning function on all paths}} subscript(_ s: Self) -> Self {} static func unreachable_static_implicit_return(_ e: MyEmptyType) -> Int {} @@ -97,16 +97,16 @@ extension MyEmptyType { } extension Never { - var i: Int {} // expected-error{{missing return in getter expected to return 'Int'}} - var n: Never {} // expected-error{{getter with uninhabited return type 'Never' is missing call to another never-returning function on all paths}} + var i: Int {} // expected-error{{missing return in getter for property expected to return 'Int'}} + var n: Never {} // expected-error{{getter for property with uninhabited return type 'Never' is missing call to another never-returning function on all paths}} static subscript(root: Never) -> A {} subscript(_ n: Never) -> Int {} subscript(_ e: Never) -> T {} - subscript(_ i: Int) -> Int {} // expected-error{{missing return in getter expected to return 'Int'}} - subscript(_ p: Int) -> T {} // expected-error{{missing return in getter expected to return 'T'}} - subscript(_ i: Int) -> Self {} // expected-error{{getter with uninhabited return type 'Never' is missing call to another never-returning function on all paths}} + subscript(_ i: Int) -> Int {} // expected-error{{missing return in getter for subscript expected to return 'Int'}} + subscript(_ p: Int) -> T {} // expected-error{{missing return in getter for subscript expected to return 'T'}} + subscript(_ i: Int) -> Self {} // expected-error{{getter for subscript with uninhabited return type 'Never' is missing call to another never-returning function on all paths}} subscript(_ s: Self) -> Self {} static func unreachable_static_implicit_return(_ n: Never) -> Int {} @@ -128,8 +128,8 @@ enum InhabitedType { subscript(_ v: MyEmptyType, e: Int) -> Never {} // Inhabited params - subscript(_ i: Int) -> Int {} // expected-error{{missing return in getter expected to return 'Int'}} + subscript(_ i: Int) -> Int {} // expected-error{{missing return in getter for subscript expected to return 'Int'}} subscript(_ j: Int) -> Void {} - subscript(_ k: Int) -> Never {} // expected-error{{getter with uninhabited return type 'Never' is missing call to another never-returning function on all paths}} + subscript(_ k: Int) -> Never {} // expected-error{{getter for subscript with uninhabited return type 'Never' is missing call to another never-returning function on all paths}} // FIXME: ^ this diagnostic should probably use the word 'subscript' rather than 'getter' } diff --git a/test/SILOptimizer/return.swift b/test/SILOptimizer/return.swift index 84147017d6506..863b34349110c 100644 --- a/test/SILOptimizer/return.swift +++ b/test/SILOptimizer/return.swift @@ -232,14 +232,14 @@ struct S_56857 { if b { return 0 } - } // expected-error {{missing return in getter expected to return 'Int'}} + } // expected-error {{missing return in getter for property expected to return 'Int'}} var y: Int { get { if b { return 0 } - } // expected-error {{missing return in getter expected to return 'Int'}} + } // expected-error {{missing return in getter for property expected to return 'Int'}} set {} } } From 35c3b9e12cce83a73357c344889b6b0ec1113b37 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 3 Jul 2025 16:39:31 -0700 Subject: [PATCH 09/10] [concurrency] Perform some fixes so that transfernonsendable_closureliterals_isolationinference.swift now passes. The reason why this failed is that concurrently to @xedin landing 79af04ccc41faa717cfa3666e492f396993fcad1, I enabled NonisolatedNonsendingByDefault on a bunch of other tests. That change broke the test and so we needed to fix it. This commit fixes a few issues that were exposed: 1. We do not propagate nonisolated(nonsending) into a closure if its inferred context isolation is global actor isolated or if the closure captures an isolated parameter. We previously just always inferred nonisolated(nonsending). Unfortunately since we do not yet have capture information in CSApply, this required us to put the isolation change into TypeCheckConcurrency.cpp and basically have function conversions of the form: ``` (function_conversion_expr type="nonisolated(nonsending) () async -> Void" (closure_expr type="() async -> ()" isolated_to_caller_isolation)) ``` Notice how we have a function conversion to nonisolated(nonsending) from a closure expr that has an isolation that is isolated_to_caller. 2. With this in hand, we found that this pattern caused us to first thunk a nonisolated(nonsending) function to an @concurrent function and then thunk that back to nonisolated(nonsending), causing the final function to always be concurrent. I put into SILGen a peephole that recognizes this pattern and emits the correct code. 3. With that in hand, we found that we were emitting nonisolated(nonsending) parameters for inheritActorContext functions. This was then fixed by @xedin in With all this in hand, closure literal isolation and all of the other RBI tests with nonisolated(nonsending) enabled pass. rdar://154969621 (cherry picked from commit 648bb8fe3027a57e5ebd743c749744472f21b7b2) --- lib/SILGen/SILGenExpr.cpp | 64 +++++++++++++++++++ lib/Sema/CSApply.cpp | 17 ----- lib/Sema/TypeCheckConcurrency.cpp | 29 ++++++++- .../attr_execution/attr_execution.swift | 6 +- .../attr_execution/conversions_silgen.swift | 6 +- ...e_closureliterals_isolationinference.swift | 4 +- 6 files changed, 99 insertions(+), 27 deletions(-) diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index f33cc526bd2d8..15686b18ac236 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -497,6 +497,10 @@ namespace { RValue emitFunctionCvtFromExecutionCallerToGlobalActor(FunctionConversionExpr *E, SGFContext C); + + RValue emitFunctionCvtForNonisolatedNonsendingClosureExpr( + FunctionConversionExpr *E, SGFContext C); + RValue visitActorIsolationErasureExpr(ActorIsolationErasureExpr *E, SGFContext C); RValue visitExtractFunctionIsolationExpr(ExtractFunctionIsolationExpr *E, @@ -2033,6 +2037,44 @@ RValueEmitter::emitFunctionCvtToExecutionCaller(FunctionConversionExpr *e, return RValue(SGF, e, destType, result); } +RValue RValueEmitter::emitFunctionCvtForNonisolatedNonsendingClosureExpr( + FunctionConversionExpr *E, SGFContext C) { + // The specific AST pattern for this looks as follows: + // + // (function_conversion_expr type="nonisolated(nonsending) () async -> Void" + // (closure_expr type="() async -> ()" isolated_to_caller_isolation)) + CanAnyFunctionType destType = + cast(E->getType()->getCanonicalType()); + auto subExpr = E->getSubExpr()->getSemanticsProvidingExpr(); + + // If we do not have a closure or if that closure is not caller isolation + // inheriting, bail. + auto *closureExpr = dyn_cast(subExpr); + if (!closureExpr || + !closureExpr->getActorIsolation().isCallerIsolationInheriting()) + return RValue(); + + // Then grab our closure type... make sure it is non isolated and then make + // sure it is the same as our destType but with nonisolated. + CanAnyFunctionType closureType = + cast(closureExpr->getType()->getCanonicalType()); + if (!closureType->getIsolation().isNonIsolated() || + closureType != + destType->withIsolation(FunctionTypeIsolation::forNonIsolated()) + ->getCanonicalType()) + return RValue(); + + // NOTE: This is a partial inline of getClosureTypeInfo. We do this so we have + // more control and make this change less viral in the compiler for 6.2. + auto newExtInfo = closureType->getExtInfo().withIsolation( + FunctionTypeIsolation::forNonIsolatedCaller()); + closureType = closureType.withExtInfo(newExtInfo); + auto info = SGF.getFunctionTypeInfo(closureType); + + auto closure = emitClosureReference(closureExpr, info); + return RValue(SGF, closureExpr, destType, closure); +} + RValue RValueEmitter::emitFunctionCvtFromExecutionCallerToGlobalActor( FunctionConversionExpr *e, SGFContext C) { // We are pattern matching a conversion sequence like the following: @@ -2144,6 +2186,28 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e, // TODO: Move this up when we can emit closures directly with C calling // convention. auto subExpr = e->getSubExpr()->getSemanticsProvidingExpr(); + + // Before we go any further into emitting the convert function expr, see if + // our SubExpr is a ClosureExpr with the exact same type as our + // FunctionConversionExpr except with the FunctionConversionExpr adding + // nonisolated(nonsending). Then see if the ClosureExpr itself (even though it + // is not nonisolated(nonsending) typed is considered to have + // nonisolated(nonsending) isolation. In such a case, emit the closure + // directly. We are going to handle it especially in closure emission to work + // around the missing information in the type. + // + // DISCUSSION: We need to do this here since in the Expression TypeChecker we + // do not have access to capture information when we would normally want to + // mark the closure type as being nonisolated(nonsending). As a result, we + // cannot know if the nonisolated(nonsending) should be overridden by for + // example an actor that is captured by the closure. So to work around this in + // Sema, we still mark the ClosureExpr as having the appropriate isolation + // even though its type does not have it... and then we work around this here + // and also in getClosureTypeInfo. + if (destType->getIsolation().isNonIsolatedCaller()) + if (auto rv = emitFunctionCvtForNonisolatedNonsendingClosureExpr(e, C)) + return rv; + // Look through `as` type ascriptions that don't induce bridging too. while (auto subCoerce = dyn_cast(subExpr)) { // Coercions that introduce bridging aren't simple type ascriptions. diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index a214f7377bea9..5fcbf38a3a07d 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -7861,23 +7861,6 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, } } - // If we have a ClosureExpr, then we can safely propagate the - // 'nonisolated(nonsending)' isolation if it's not explicitly - // marked as `@concurrent`. - if (toEI.getIsolation().isNonIsolatedCaller() && - (fromEI.getIsolation().isNonIsolated() && - !isClosureMarkedAsConcurrent(expr))) { - auto newFromFuncType = fromFunc->withIsolation( - FunctionTypeIsolation::forNonIsolatedCaller()); - if (applyTypeToClosureExpr(cs, expr, newFromFuncType)) { - fromFunc = newFromFuncType->castTo(); - // Propagating 'nonisolated(nonsending)' might have satisfied the entire - // conversion. If so, we're done, otherwise keep converting. - if (fromFunc->isEqual(toType)) - return expr; - } - } - if (ctx.LangOpts.isDynamicActorIsolationCheckingEnabled()) { // Passing a synchronous global actor-isolated function value and // parameter that expects a synchronous non-isolated function type could diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index c648c6a3c62e2..2ae325f28b30e 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4987,8 +4987,33 @@ ActorIsolation ActorIsolationChecker::determineClosureIsolation( closure->getParent(), getClosureActorIsolation); preconcurrency |= parentIsolation.preconcurrency(); - return computeClosureIsolationFromParent(closure, parentIsolation, - checkIsolatedCapture); + auto normalIsolation = computeClosureIsolationFromParent( + closure, parentIsolation, checkIsolatedCapture); + + // The solver has to be conservative and produce a conversion to + // `nonisolated(nonsending)` because at solution application time + // we don't yet know whether there are any captures which would + // make closure isolated. + // + // At this point we know that closure is not explicitly annotated with + // global actor, nonisolated/@concurrent attributes and doesn't have + // isolated parameters. If our closure is nonisolated and we have a + // conversion to nonisolated(nonsending), then we should respect that. + if (auto *explicitClosure = dyn_cast(closure); + !normalIsolation.isGlobalActor()) { + if (auto *fce = + dyn_cast_or_null(Parent.getAsExpr())) { + auto expectedIsolation = + fce->getType()->castTo()->getIsolation(); + if (expectedIsolation.isNonIsolatedCaller()) { + auto captureInfo = explicitClosure->getCaptureInfo(); + if (!captureInfo.getIsolatedParamCapture()) + return ActorIsolation::forCallerIsolationInheriting(); + } + } + } + + return normalIsolation; }(); // Apply computed preconcurrency. diff --git a/test/Concurrency/attr_execution/attr_execution.swift b/test/Concurrency/attr_execution/attr_execution.swift index 93702c1c8aacb..c9f855cb770c9 100644 --- a/test/Concurrency/attr_execution/attr_execution.swift +++ b/test/Concurrency/attr_execution/attr_execution.swift @@ -18,7 +18,7 @@ func callerTest() async {} struct Test { // CHECK-LABEL: // closure #1 in variable initialization expression of Test.x // CHECK: // Isolation: caller_isolation_inheriting - // CHECK: sil private [ossa] @$s14attr_execution4TestV1xyyYaYCcvpfiyyYaYCcfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () + // CHECK: sil private [ossa] @$s14attr_execution4TestV1xyyYaYCcvpfiyyYacfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () var x: () async -> Void = {} // CHECK-LABEL: // Test.test() @@ -67,7 +67,7 @@ func takesClosure(fn: () async -> Void) { } // CHECK-LABEL: sil hidden [ossa] @$s14attr_execution11testClosureyyF : $@convention(thin) () -> () -// CHECK: [[CLOSURE:%.*]] = function_ref @$s14attr_execution11testClosureyyFyyYaYCXEfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () +// CHECK: [[CLOSURE:%.*]] = function_ref @$s14attr_execution11testClosureyyFyyYaXEfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () // CHECK: [[THUNKED_CLOSURE:%.*]] = thin_to_thick_function %0 to $@noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () // CHECK: [[TAKES_CLOSURE:%.*]] = function_ref @$s14attr_execution12takesClosure2fnyyyYaYCXE_tF : $@convention(thin) (@guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> ()) -> () // CHECK: apply [[TAKES_CLOSURE]]([[THUNKED_CLOSURE]]) @@ -75,7 +75,7 @@ func takesClosure(fn: () async -> Void) { // CHECK-LABEL: // closure #1 in testClosure() // CHECK: // Isolation: caller_isolation_inheriting -// CHECK: sil private [ossa] @$s14attr_execution11testClosureyyFyyYaYCXEfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () +// CHECK: sil private [ossa] @$s14attr_execution11testClosureyyFyyYaXEfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () func testClosure() { takesClosure { } diff --git a/test/Concurrency/attr_execution/conversions_silgen.swift b/test/Concurrency/attr_execution/conversions_silgen.swift index 7b97a59fc57e5..2271c686ed172 100644 --- a/test/Concurrency/attr_execution/conversions_silgen.swift +++ b/test/Concurrency/attr_execution/conversions_silgen.swift @@ -421,7 +421,7 @@ func conversionsFromSyncToAsync(_ x: @escaping @Sendable (NonSendableKlass) -> V } func testThatClosuresAssumeIsolation(fn: inout nonisolated(nonsending) (Int) async -> Void) { - // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFyyYaYCcfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () + // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFyyYacfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () { // CHECK: bb0([[EXECUTOR:%.*]] : @guaranteed $Optional): // CHECK: hop_to_executor [[EXECUTOR]] let _: nonisolated(nonsending) () async -> Void = { @@ -430,7 +430,7 @@ func testThatClosuresAssumeIsolation(fn: inout nonisolated(nonsending) (Int) asy func testParam(_: nonisolated(nonsending) () async throws -> Void) {} - // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFyyYaYCXEfU0_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> @error any Error + // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFyyYaXEfU0_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () { // CHECK: bb0([[EXECUTOR:%.*]] : @guaranteed $Optional): // CHECK: hop_to_executor [[EXECUTOR]] testParam { 42 } @@ -440,7 +440,7 @@ func testThatClosuresAssumeIsolation(fn: inout nonisolated(nonsending) (Int) asy // CHECK: hop_to_executor [[GENERIC_EXECUTOR]] testParam { @concurrent in 42 } - // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFySiYaYCcfU2_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, Int) -> () + // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFySiYacfU2_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, Int) -> () { // CHECK: bb0([[EXECUTOR:%.*]] : @guaranteed $Optional, %1 : $Int): // CHECK: hop_to_executor [[EXECUTOR]] fn = { _ in } diff --git a/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift b/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift index 95e0937110421..fb3669656dfd4 100644 --- a/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift +++ b/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift @@ -1,6 +1,6 @@ -// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -o - | %FileCheck %s +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -o - 2>/dev/null | %FileCheck %s // RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null -verify-additional-prefix ni- -// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -o - -enable-upcoming-feature NonisolatedNonsendingByDefault | %FileCheck %s +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -o - -enable-upcoming-feature NonisolatedNonsendingByDefault 2>/dev/null | %FileCheck %s // RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null -enable-upcoming-feature NonisolatedNonsendingByDefault -verify-additional-prefix ni-ns- // REQUIRES: concurrency From 1f9e30276aeb73731092996b1134fde1deae4b70 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 10 Jul 2025 10:46:31 -0700 Subject: [PATCH 10/10] [rbi] Teach SendNonSendable how to more aggressively suppress sending errors around obfuscated Sendable functions Specifically the type checker to work around interface types not having isolation introduces casts into the AST that enrich the AST with isolation information. Part of that information is Sendable. This means that we can sometimes lose due to conversions that a function is actually Sendable. To work around this, we today suppress those errors when they are emitted (post 6.2, we should just change their classification as being Sendable... but I don't want to make that change now). This change just makes the pattern matching for these conversions handle more cases so that transfernonsendable_closureliterals_isolationinference.swift now passes. --- .../swift/SILOptimizer/Utils/PartitionUtils.h | 32 +++++++++++++++++-- ...sfernonsendable_global_actor_sending.swift | 5 ++- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/include/swift/SILOptimizer/Utils/PartitionUtils.h b/include/swift/SILOptimizer/Utils/PartitionUtils.h index d0f99cd2d5cc6..dfddfb537a4e3 100644 --- a/include/swift/SILOptimizer/Utils/PartitionUtils.h +++ b/include/swift/SILOptimizer/Utils/PartitionUtils.h @@ -1598,9 +1598,32 @@ struct PartitionOpEvaluator { } private: - bool isConvertFunctionFromSendableType(SILValue equivalenceClassRep) const { + /// To work around not having isolation in interface types, the type checker + /// inserts casts and other AST nodes that are used to enrich the AST with + /// isolation information. This results in Sendable functions being + /// wrapped/converted/etc in ways that hide the Sendability. This helper looks + /// through these conversions/wrappers/thunks to see if the original + /// underlying function is Sendable. + /// + /// The two ways this can happen is that we either get an actual function_ref + /// that is Sendable or we get a convert function with a Sendable operand. + bool isHiddenSendableFunctionType(SILValue equivalenceClassRep) const { SILValue valueToTest = equivalenceClassRep; while (true) { + if (auto *pai = dyn_cast(valueToTest)) { + if (auto *calleeFunction = pai->getCalleeFunction()) { + if (pai->getNumArguments() >= 1 && + pai->getArgument(0)->getType().isFunction() && + calleeFunction->isThunk()) { + valueToTest = pai->getArgument(0); + continue; + } + + if (calleeFunction->getLoweredFunctionType()->isSendable()) + return true; + } + } + if (auto *i = dyn_cast(valueToTest)) { valueToTest = i->getOperand(); continue; @@ -1612,6 +1635,9 @@ struct PartitionOpEvaluator { break; } + if (auto *fn = dyn_cast(valueToTest)) + return fn->getReferencedFunction()->getLoweredFunctionType()->isSendable(); + auto *cvi = dyn_cast(valueToTest); if (!cvi) return false; @@ -1644,7 +1670,7 @@ struct PartitionOpEvaluator { // See if we have a convert function from a `@Sendable` type. In this // case, we want to squelch the error. - if (isConvertFunctionFromSendableType(equivalenceClassRep)) + if (isHiddenSendableFunctionType(equivalenceClassRep)) return; } @@ -1689,7 +1715,7 @@ struct PartitionOpEvaluator { // See if we have a convert function from a `@Sendable` type. In this // case, we want to squelch the error. - if (isConvertFunctionFromSendableType(equivalenceClassRep)) + if (isHiddenSendableFunctionType(equivalenceClassRep)) return; } } diff --git a/test/Concurrency/transfernonsendable_global_actor_sending.swift b/test/Concurrency/transfernonsendable_global_actor_sending.swift index f4d0c9fbec375..37c446a1eee62 100644 --- a/test/Concurrency/transfernonsendable_global_actor_sending.swift +++ b/test/Concurrency/transfernonsendable_global_actor_sending.swift @@ -34,9 +34,8 @@ func useValue(_ t: T) {} @MainActor func testGlobalFakeInit() { let ns = NonSendableKlass() - // Will be resolved once @MainActor is @Sendable. - Task.fakeInit { @MainActor in // expected-error {{passing closure as a 'sending' parameter risks causing data races between main actor-isolated code and concurrent execution of the closure}} - print(ns) // expected-note {{closure captures 'ns' which is accessible to main actor-isolated code}} + Task.fakeInit { @MainActor in + print(ns) } useValue(ns)