Skip to content

Commit cd8bfe4

Browse files
authored
Merge pull request #74879 from gottesmm/release/6.0-rdar130915737-part1
[6.0][region-isolation] Change capturing a value into an async let that is not further sent into an actor isolated function to use a new style error.
2 parents a8a60dd + bd5490a commit cd8bfe4

File tree

5 files changed

+355
-338
lines changed

5 files changed

+355
-338
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,10 @@ NOTE(regionbasedisolation_named_transfer_non_transferrable, none,
990990
NOTE(regionbasedisolation_named_transfer_non_transferrable_callee, none,
991991
"sending %1%0 to %2 %3 %4 risks causing data races between %2 and %5 uses",
992992
(Identifier, StringRef, ActorIsolation, DescriptiveDeclKind, DeclName, StringRef))
993+
NOTE(regionbasedisolation_named_nonisolated_asynclet_name, none,
994+
"sending %0 into async let risks causing data races between async let uses and local uses",
995+
(Identifier))
996+
993997
NOTE(regionbasedisolation_named_transfer_into_sending_param, none,
994998
"%0%1 is passed as a 'sending' parameter; Uses in callee may race with later %0uses",
995999
(StringRef, Identifier))

include/swift/SILOptimizer/Analysis/RegionAnalysis.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,20 @@ class RegionAnalysisValueMap;
2828

2929
namespace regionanalysisimpl {
3030

31+
#ifndef NDEBUG
32+
/// Global bool set only when asserts are enabled to ease debugging by causing
33+
/// unknown pattern errors to cause an assert so we drop into the debugger.
34+
extern bool AbortOnUnknownPatternMatchError;
35+
#endif
36+
37+
static inline bool shouldAbortOnUnknownPatternMatchError() {
38+
#ifndef NDEBUG
39+
return AbortOnUnknownPatternMatchError;
40+
#else
41+
return false;
42+
#endif
43+
}
44+
3145
using TransferringOperandSetFactory = Partition::TransferringOperandSetFactory;
3246
using Element = PartitionPrimitives::Element;
3347
using Region = PartitionPrimitives::Region;

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,19 @@ using namespace swift::PartitionPrimitives;
4747
using namespace swift::PatternMatch;
4848
using namespace swift::regionanalysisimpl;
4949

50-
static llvm::cl::opt<bool> AbortOnUnknownPatternMatchError(
50+
#ifndef NDEBUG
51+
52+
bool swift::regionanalysisimpl::AbortOnUnknownPatternMatchError = false;
53+
54+
static llvm::cl::opt<bool, true> AbortOnUnknownPatternMatchErrorCmdLine(
5155
"sil-region-isolation-assert-on-unknown-pattern",
5256
llvm::cl::desc("Abort if SIL region isolation detects an unknown pattern. "
5357
"Intended only to be used when debugging the compiler!"),
54-
llvm::cl::init(false), llvm::cl::Hidden);
58+
llvm::cl::Hidden,
59+
llvm::cl::location(
60+
swift::regionanalysisimpl::AbortOnUnknownPatternMatchError));
61+
62+
#endif
5563

5664
//===----------------------------------------------------------------------===//
5765
// MARK: Utilities
@@ -1197,7 +1205,7 @@ struct PartitionOpBuilder {
11971205
}
11981206

11991207
void addUnknownPatternError(SILValue value) {
1200-
if (AbortOnUnknownPatternMatchError) {
1208+
if (shouldAbortOnUnknownPatternMatchError()) {
12011209
llvm::report_fatal_error(
12021210
"RegionIsolation: Aborting on unknown pattern match error");
12031211
}

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 103 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,19 @@ class UseAfterTransferDiagnosticEmitter {
574574
emitRequireInstDiagnostics();
575575
}
576576

577+
void emitNamedAsyncLetNoIsolationCrossingError(SILLocation loc,
578+
Identifier name) {
579+
// Emit the short error.
580+
diagnoseError(loc, diag::regionbasedisolation_named_transfer_yields_race,
581+
name)
582+
.highlight(loc.getSourceRange())
583+
.limitBehaviorIf(getBehaviorLimit());
584+
585+
diagnoseNote(
586+
loc, diag::regionbasedisolation_named_nonisolated_asynclet_name, name);
587+
emitRequireInstDiagnostics();
588+
}
589+
577590
void emitTypedIsolationCrossing(SILLocation loc, Type inferredType,
578591
ApplyIsolationCrossing isolationCrossing) {
579592
diagnoseError(
@@ -664,6 +677,11 @@ class UseAfterTransferDiagnosticEmitter {
664677
}
665678

666679
void emitUnknownPatternError() {
680+
if (shouldAbortOnUnknownPatternMatchError()) {
681+
llvm::report_fatal_error(
682+
"RegionIsolation: Aborting on unknown pattern match error");
683+
}
684+
667685
diagnoseError(transferOp->getUser(),
668686
diag::regionbasedisolation_unknown_pattern)
669687
.limitBehaviorIf(getBehaviorLimit());
@@ -838,7 +856,7 @@ struct UseAfterTransferDiagnosticInferrer::AutoClosureWalker : ASTWalker {
838856
: foundTypeInfo(foundTypeInfo), targetDecl(targetDecl),
839857
targetDeclIsolationInfo(targetDeclIsolationInfo) {}
840858

841-
Expr *lookThroughExpr(Expr *expr) {
859+
Expr *lookThroughArgExpr(Expr *expr) {
842860
while (true) {
843861
if (auto *memberRefExpr = dyn_cast<MemberRefExpr>(expr)) {
844862
expr = memberRefExpr->getBase();
@@ -866,67 +884,85 @@ struct UseAfterTransferDiagnosticInferrer::AutoClosureWalker : ASTWalker {
866884

867885
PreWalkResult<Expr *> walkToExprPre(Expr *expr) override {
868886
if (auto *declRef = dyn_cast<DeclRefExpr>(expr)) {
869-
// If this decl ref expr was not visited as part of a callExpr, add it as
870-
// something without isolation crossing.
887+
// If this decl ref expr was not visited as part of a callExpr and is our
888+
// target decl... emit a simple async let error.
871889
if (!visitedCallExprDeclRefExprs.count(declRef)) {
872890
if (declRef->getDecl() == targetDecl) {
873-
visitedCallExprDeclRefExprs.insert(declRef);
874891
foundTypeInfo.diagnosticEmitter
875-
.emitTypedRaceWithUnknownIsolationCrossing(
876-
foundTypeInfo.baseLoc, declRef->findOriginalType());
892+
.emitNamedAsyncLetNoIsolationCrossingError(
893+
foundTypeInfo.baseLoc, targetDecl->getBaseIdentifier());
877894
return Action::Continue(expr);
878895
}
879896
}
880897
}
881898

899+
// If we have a call expr, see if any of its arguments will cause our sent
900+
// value to be transferred into another isolation domain.
882901
if (auto *callExpr = dyn_cast<CallExpr>(expr)) {
883-
if (auto isolationCrossing = callExpr->getIsolationCrossing()) {
884-
// Search callExpr's arguments to see if we have our targetDecl.
885-
auto *argList = callExpr->getArgs();
886-
for (auto pair : llvm::enumerate(argList->getArgExprs())) {
887-
auto *arg = lookThroughExpr(pair.value());
888-
if (auto *declRef = dyn_cast<DeclRefExpr>(arg)) {
889-
if (declRef->getDecl() == targetDecl) {
890-
// Found our target!
891-
visitedCallExprDeclRefExprs.insert(declRef);
892-
893-
// See if we can find a valueDecl/name for our callee so we can
894-
// emit a nicer error.
895-
ConcreteDeclRef concreteDecl =
896-
callExpr->getDirectCallee()->getReferencedDecl();
897-
898-
// If we do not find a direct one, see if we are calling a method
899-
// on a nominal type.
900-
if (!concreteDecl) {
901-
if (auto *dot = dyn_cast<DotSyntaxCallExpr>(
902-
callExpr->getDirectCallee())) {
903-
concreteDecl = dot->getSemanticFn()->getReferencedDecl();
904-
}
905-
}
906-
907-
if (concreteDecl) {
908-
auto *valueDecl = concreteDecl.getDecl();
909-
assert(valueDecl &&
910-
"Should be non-null if concreteDecl is valid");
911-
if (valueDecl->hasName()) {
912-
foundTypeInfo.diagnosticEmitter
913-
.emitNamedIsolationCrossingError(
914-
foundTypeInfo.baseLoc,
915-
targetDecl->getBaseIdentifier(),
916-
targetDeclIsolationInfo, *isolationCrossing,
917-
valueDecl->getName(),
918-
valueDecl->getDescriptiveKind());
919-
return Action::Continue(expr);
920-
}
921-
}
922-
923-
// Otherwise default back to the "callee" error.
924-
foundTypeInfo.diagnosticEmitter.emitNamedIsolationCrossingError(
925-
foundTypeInfo.baseLoc, targetDecl->getBaseIdentifier(),
926-
targetDeclIsolationInfo, *isolationCrossing);
927-
return Action::Continue(expr);
928-
}
902+
// Search callExpr's arguments to see if we have our targetDecl.
903+
auto *argList = callExpr->getArgs();
904+
for (auto pair : llvm::enumerate(argList->getArgExprs())) {
905+
auto *arg = lookThroughArgExpr(pair.value());
906+
auto *declRef = dyn_cast<DeclRefExpr>(arg);
907+
if (!declRef)
908+
continue;
909+
910+
if (declRef->getDecl() != targetDecl)
911+
continue;
912+
913+
// Found our target!
914+
visitedCallExprDeclRefExprs.insert(declRef);
915+
916+
auto isolationCrossing = callExpr->getIsolationCrossing();
917+
918+
// If we do not have an isolation crossing, then we must be just sending
919+
// a value in a nonisolated fashion into an async let. So emit the
920+
// simple async let error.
921+
if (!isolationCrossing) {
922+
foundTypeInfo.diagnosticEmitter
923+
.emitNamedAsyncLetNoIsolationCrossingError(
924+
foundTypeInfo.baseLoc, targetDecl->getBaseIdentifier());
925+
continue;
926+
}
927+
928+
// Otherwise, we are calling an actor isolated function in the async
929+
// let. Emit a better error.
930+
931+
// See if we can find a valueDecl/name for our callee so we can
932+
// emit a nicer error.
933+
ConcreteDeclRef concreteDecl =
934+
callExpr->getDirectCallee()->getReferencedDecl();
935+
936+
// If we do not find a direct one, see if we are calling a method
937+
// on a nominal type.
938+
if (!concreteDecl) {
939+
if (auto *dot =
940+
dyn_cast<DotSyntaxCallExpr>(callExpr->getDirectCallee())) {
941+
concreteDecl = dot->getSemanticFn()->getReferencedDecl();
942+
}
943+
}
944+
945+
if (!concreteDecl)
946+
continue;
947+
948+
auto *valueDecl = concreteDecl.getDecl();
949+
assert(valueDecl && "Should be non-null if concreteDecl is valid");
950+
951+
if (auto isolationCrossing = callExpr->getIsolationCrossing()) {
952+
// If we have an isolation crossing, use that information.
953+
if (valueDecl->hasName()) {
954+
foundTypeInfo.diagnosticEmitter.emitNamedIsolationCrossingError(
955+
foundTypeInfo.baseLoc, targetDecl->getBaseIdentifier(),
956+
targetDeclIsolationInfo, *isolationCrossing,
957+
valueDecl->getName(), valueDecl->getDescriptiveKind());
958+
continue;
929959
}
960+
961+
// Otherwise default back to the "callee" error.
962+
foundTypeInfo.diagnosticEmitter.emitNamedIsolationCrossingError(
963+
foundTypeInfo.baseLoc, targetDecl->getBaseIdentifier(),
964+
targetDeclIsolationInfo, *isolationCrossing);
965+
continue;
930966
}
931967
}
932968
}
@@ -1058,6 +1094,11 @@ void TransferNonSendableImpl::emitUseAfterTransferDiagnostics() {
10581094
// tells the user to file a bug. This importantly ensures that we can
10591095
// guarantee that we always find the require if we successfully compile.
10601096
if (!didEmitRequireNote) {
1097+
if (shouldAbortOnUnknownPatternMatchError()) {
1098+
llvm::report_fatal_error(
1099+
"RegionIsolation: Aborting on unknown pattern match error");
1100+
}
1101+
10611102
diagnoseError(transferOp, diag::regionbasedisolation_unknown_pattern);
10621103
continue;
10631104
}
@@ -1116,6 +1157,11 @@ class TransferNonTransferrableDiagnosticEmitter {
11161157
}
11171158

11181159
void emitUnknownPatternError() {
1160+
if (shouldAbortOnUnknownPatternMatchError()) {
1161+
llvm::report_fatal_error(
1162+
"RegionIsolation: Aborting on unknown pattern match error");
1163+
}
1164+
11191165
diagnoseError(getOperand()->getUser(),
11201166
diag::regionbasedisolation_unknown_pattern)
11211167
.limitBehaviorIf(getBehaviorLimit());
@@ -1601,6 +1647,11 @@ struct DiagnosticEvaluator final
16011647
}
16021648

16031649
void handleUnknownCodePattern(const PartitionOp &op) const {
1650+
if (shouldAbortOnUnknownPatternMatchError()) {
1651+
llvm::report_fatal_error(
1652+
"RegionIsolation: Aborting on unknown pattern match error");
1653+
}
1654+
16041655
diagnoseError(op.getSourceInst(),
16051656
diag::regionbasedisolation_unknown_pattern);
16061657
}

0 commit comments

Comments
 (0)