Skip to content

[rbi] Small tweaks to the closure patch #78837 #79028

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -777,8 +777,9 @@ static bool simplifyBlocksWithCallsToNoReturn(SILBasicBlock &BB,

// If we have an ignored use whose operand is our no return call, ignore it.
if (auto *i = dyn_cast<IgnoredUseInst>(currInst)) {
if (auto *svi = dyn_cast<SingleValueInstruction>(i->getOperand());
svi && getAsCallToNoReturn(svi)) {
// This handles try_apply, apply, begin_apply.
if (auto *inst = i->getOperand()->getDefiningInstructionOrTerminator();
inst && inst == noReturnCall) {
return false;
}
}
Expand Down
16 changes: 9 additions & 7 deletions lib/SILOptimizer/Mandatory/SendNonSendable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,14 +294,16 @@ findClosureUse(Operand *initialOperand) {
// immediately invoked. In such a case, we can emit a better diagnostic in
// the called closure.
if (auto fas = FullApplySite::isa(op->getUser())) {
if (auto *f = fas.getCalleeFunction();
f && f->getDeclRef().getClosureExpr()) {
auto *fArg = f->getArgument(fas.getCalleeArgIndex(*op));
for (auto *use : fArg->getUses()) {
if (visitedOperand.insert(use).second)
worklist.emplace_back(use, fArg);
if (auto *f = fas.getCalleeFunction()) {
auto *fArg = cast<SILFunctionArgument>(
f->getArgument(fas.getCalleeArgIndex(*op)));
if (fArg->isClosureCapture()) {
for (auto *use : fArg->getUses()) {
if (visitedOperand.insert(use).second)
worklist.emplace_back(use, fArg);
}
continue;
}
continue;
}
}

Expand Down
6 changes: 6 additions & 0 deletions test/Concurrency/transfernonsendable_sending_params.swift
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,12 @@ func taskIsolatedCaptureInSendingClosureLiteral(_ x: NonSendableKlass) {
}()
}

Task { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}}
{ // expected-note {{closure captures 'x' which is accessible to code in the current task}}
print($0)
}(x)
}

takeClosure { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}}
print(x) // expected-note {{closure captures 'x' which is accessible to code in the current task}}
}
Expand Down
50 changes: 42 additions & 8 deletions test/SILOptimizer/noreturn_folding.sil
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// RUN: %target-sil-opt -module-name Swift -enable-sil-verify-all -noreturn-folding < %s | %FileCheck %s
// RUN: %target-sil-opt -enable-sil-verify-all -noreturn-folding -verify %s | %FileCheck %s

import Swift
import Builtin

enum Never {}

struct Int64 {
var value: Builtin.Int64
}
sil @exit : $@convention(thin) (Builtin.Int32) -> Never
sil @returnNever : $@convention(thin) () -> Never
sil @returnNeverThrows : $@convention(thin) () -> (Never, @error Error)
sil @returnNeverCoroutine : $@yield_once @convention(thin) () -> @yields Never
sil @doSomething : $@convention(thin) () -> ()

// We used to crash on this IR. We would delete "%4" while there is still a
// (dead) user "%7" around.
Expand All @@ -15,15 +16,17 @@ struct Int64 {
// CHECK: %[[E:.+]] = function_ref @exit
// CHECK: apply %[[E]]
// CHECK: unreachable

// CHECK: } // end sil function 'unreachable_outside_block_user'
sil private @unreachable_outside_block_user : $@convention(thin) () -> Int64 {
bb0:
%0 = integer_literal $Builtin.Int1, -1
%1 = integer_literal $Builtin.Int32, 3
// function_ref exit
%2 = function_ref @exit : $@convention(thin) (Builtin.Int32) -> Never
%3 = apply %2(%1) : $@convention(thin) (Builtin.Int32) -> Never
// expected-note @-1 {{a call to a never-returning function}}
%4 = integer_literal $Builtin.Int64, 7
// expected-warning @-1 {{will never be executed}}
cond_br %0, bb1, bb2

bb1:
Expand All @@ -42,4 +45,35 @@ bb3 (%11: $Int64):
return %11 : $Int64
}

sil @exit : $@convention(thin) (Builtin.Int32) -> Never
// Make sure we do not emit any error here.
sil @ignore_use_apply : $@convention(thin) () -> () {
bb0:
%0 = function_ref @returnNever : $@convention(thin) () -> Never
%1 = apply %0() : $@convention(thin) () -> Never
ignored_use %1 : $Never
unreachable
}

// Make sure we do not emit any error here.
sil [ossa] @ignore_use_try_apply : $@convention(thin) () -> () {
bb0:
%0 = function_ref @returnNeverThrows : $@convention(thin) () -> (Never, @error Error)
try_apply %0() : $@convention(thin) () -> (Never, @error Error), normal bb1, error bb2

bb1(%2 : $Never):
ignored_use %2 : $Never
unreachable

bb2(%5 : @owned $Error):
%6 = builtin "unexpectedError"(%5 : $Error) : $()
unreachable
}

sil [ossa] @ignore_use_begin_apply : $@convention(thin) () -> () {
bb0:
%0 = function_ref @returnNeverCoroutine : $@yield_once @convention(thin) () -> @yields Never
(%1, %2) = begin_apply %0() : $@yield_once @convention(thin) () -> @yields Never
ignored_use %1
end_apply %2 as $()
unreachable
}