Skip to content

Commit a13c1dc

Browse files
authored
Merge pull request #74869 from gottesmm/rdar130915737
[region-isolation] Improve async let errors to always use a new style error.
2 parents 1f2ff67 + 31df5f2 commit a13c1dc

File tree

5 files changed

+325
-341
lines changed

5 files changed

+325
-341
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,10 @@ NOTE(regionbasedisolation_named_transfer_non_transferrable, none,
994994
NOTE(regionbasedisolation_named_transfer_non_transferrable_callee, none,
995995
"sending %1%0 to %2 %3 %4 risks causing data races between %2 and %5 uses",
996996
(Identifier, StringRef, ActorIsolation, DescriptiveDeclKind, DeclName, StringRef))
997+
NOTE(regionbasedisolation_named_nonisolated_asynclet_name, none,
998+
"sending %0 into async let risks causing data races between async let uses and local uses",
999+
(Identifier))
1000+
9971001
NOTE(regionbasedisolation_named_transfer_into_sending_param, none,
9981002
"%0%1 is passed as a 'sending' parameter; Uses in callee may race with later %0uses",
9991003
(StringRef, Identifier))

include/swift/SILOptimizer/Analysis/RegionAnalysis.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ 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+
3137
using TransferringOperandSetFactory = Partition::TransferringOperandSetFactory;
3238
using Element = PartitionPrimitives::Element;
3339
using Region = PartitionPrimitives::Region;

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,19 @@ using namespace swift::PartitionPrimitives;
4848
using namespace swift::PatternMatch;
4949
using namespace swift::regionanalysisimpl;
5050

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

5765
//===----------------------------------------------------------------------===//
5866
// MARK: Utilities

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

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

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

667680
void emitUnknownPatternError() {
681+
if (AbortOnUnknownPatternMatchError) {
682+
llvm::report_fatal_error(
683+
"RegionIsolation: Aborting on unknown pattern match error");
684+
}
685+
668686
diagnoseError(transferOp->getUser(),
669687
diag::regionbasedisolation_unknown_pattern)
670688
.limitBehaviorIf(getBehaviorLimit());
@@ -839,7 +857,7 @@ struct UseAfterTransferDiagnosticInferrer::AutoClosureWalker : ASTWalker {
839857
: foundTypeInfo(foundTypeInfo), targetDecl(targetDecl),
840858
targetDeclIsolationInfo(targetDeclIsolationInfo) {}
841859

842-
Expr *lookThroughExpr(Expr *expr) {
860+
Expr *lookThroughArgExpr(Expr *expr) {
843861
while (true) {
844862
if (auto *memberRefExpr = dyn_cast<MemberRefExpr>(expr)) {
845863
expr = memberRefExpr->getBase();
@@ -867,67 +885,85 @@ struct UseAfterTransferDiagnosticInferrer::AutoClosureWalker : ASTWalker {
867885

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

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

11191160
void emitUnknownPatternError() {
1161+
if (AbortOnUnknownPatternMatchError) {
1162+
llvm::report_fatal_error(
1163+
"RegionIsolation: Aborting on unknown pattern match error");
1164+
}
1165+
11201166
diagnoseError(getOperand()->getUser(),
11211167
diag::regionbasedisolation_unknown_pattern)
11221168
.limitBehaviorIf(getBehaviorLimit());
@@ -1602,6 +1648,11 @@ struct DiagnosticEvaluator final
16021648
}
16031649

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

0 commit comments

Comments
 (0)