@@ -530,9 +530,8 @@ ActorIsolationRestriction ActorIsolationRestriction::forDeclaration(
530
530
case DeclKind::Func:
531
531
case DeclKind::Subscript: {
532
532
// Local captures are checked separately.
533
- if (cast<ValueDecl>(decl)->isLocalCapture ()) {
534
- return forLocalCapture (decl->getDeclContext ());
535
- }
533
+ if (cast<ValueDecl>(decl)->isLocalCapture ())
534
+ return forUnrestricted ();
536
535
537
536
// 'let' declarations are immutable, so they can be accessed across
538
537
// actors.
@@ -886,6 +885,11 @@ namespace {
886
885
SmallVector<const DeclContext *, 4 > contextStack;
887
886
SmallVector<ApplyExpr*, 4 > applyStack;
888
887
888
+ // / Keeps track of the capture context of variables that have been
889
+ // / explicitly captured in closures.
890
+ llvm::SmallDenseMap<VarDecl *, TinyPtrVector<const DeclContext *>>
891
+ captureContexts;
892
+
889
893
using MutableVarSource = llvm::PointerUnion<DeclRefExpr *, InOutExpr *>;
890
894
using MutableVarParent = llvm::PointerUnion<InOutExpr *, LoadExpr *>;
891
895
@@ -1134,6 +1138,13 @@ namespace {
1134
1138
if (isa<ObjCSelectorExpr>(expr))
1135
1139
return { false , expr };
1136
1140
1141
+ // Track the capture contexts for variables.
1142
+ if (auto captureList = dyn_cast<CaptureListExpr>(expr)) {
1143
+ for (const auto &entry : captureList->getCaptureList ()) {
1144
+ captureContexts[entry.Var ].push_back (captureList->getClosureBody ());
1145
+ }
1146
+ }
1147
+
1137
1148
return { true , expr };
1138
1149
}
1139
1150
@@ -1156,6 +1167,17 @@ namespace {
1156
1167
mutableLocalVarParent.erase (inoutExpr);
1157
1168
}
1158
1169
1170
+ // Remove the tracked capture contexts.
1171
+ if (auto captureList = dyn_cast<CaptureListExpr>(expr)) {
1172
+ for (const auto &entry : captureList->getCaptureList ()) {
1173
+ auto &contexts = captureContexts[entry.Var ];
1174
+ assert (contexts.back () == captureList->getClosureBody ());
1175
+ contexts.pop_back ();
1176
+ if (contexts.empty ())
1177
+ captureContexts.erase (entry.Var );
1178
+ }
1179
+ }
1180
+
1159
1181
return expr;
1160
1182
}
1161
1183
@@ -1257,7 +1279,6 @@ namespace {
1257
1279
auto isolation = ActorIsolationRestriction::forDeclaration (decl);
1258
1280
switch (isolation) {
1259
1281
case ActorIsolationRestriction::Unrestricted:
1260
- case ActorIsolationRestriction::LocalCapture:
1261
1282
case ActorIsolationRestriction::Unsafe:
1262
1283
break ;
1263
1284
case ActorIsolationRestriction::CrossGlobalActor:
@@ -1526,13 +1547,95 @@ namespace {
1526
1547
llvm_unreachable (" unhandled actor isolation kind!" );
1527
1548
}
1528
1549
1550
+ // / Find the innermost context in which this declaration was explicitly
1551
+ // / captured.
1552
+ const DeclContext *findCapturedDeclContext (ValueDecl *value) {
1553
+ assert (value->isLocalCapture ());
1554
+ auto var = dyn_cast<VarDecl>(value);
1555
+ if (!var)
1556
+ return value->getDeclContext ();
1557
+
1558
+ auto knownContexts = captureContexts.find (var);
1559
+ if (knownContexts == captureContexts.end ())
1560
+ return value->getDeclContext ();
1561
+
1562
+ return knownContexts->second .back ();
1563
+ }
1564
+
1565
+ // / Check a reference to a local capture.
1566
+ bool checkLocalCapture (
1567
+ ConcreteDeclRef valueRef, SourceLoc loc, DeclRefExpr *declRefExpr) {
1568
+ auto value = valueRef.getDecl ();
1569
+
1570
+ // Check whether we are in a context that will not execute concurrently
1571
+ // with the context of 'self'. If not, it's safe.
1572
+ if (!mayExecuteConcurrentlyWith (
1573
+ getDeclContext (), findCapturedDeclContext (value)))
1574
+ return false ;
1575
+
1576
+ // Check whether this is a local variable, in which case we can
1577
+ // determine whether it was safe to access concurrently.
1578
+ if (auto var = dyn_cast<VarDecl>(value)) {
1579
+ auto parent = mutableLocalVarParent[declRefExpr];
1580
+
1581
+ // If the variable is immutable, it's fine so long as it involves
1582
+ // ConcurrentValue types.
1583
+ //
1584
+ // When flow-sensitive concurrent captures are enabled, we also
1585
+ // allow reads, depending on a SIL diagnostic pass to identify the
1586
+ // remaining race conditions.
1587
+ if (!var->supportsMutation () ||
1588
+ (ctx.LangOpts .EnableExperimentalFlowSensitiveConcurrentCaptures &&
1589
+ parent.dyn_cast <LoadExpr *>())) {
1590
+ return diagnoseNonConcurrentTypesInReference (
1591
+ valueRef, getDeclContext (), loc,
1592
+ ConcurrentReferenceKind::LocalCapture);
1593
+ }
1594
+
1595
+ // Otherwise, we have concurrent access. Complain.
1596
+ ctx.Diags .diagnose (
1597
+ loc, diag::concurrent_access_of_local_capture,
1598
+ parent.dyn_cast <LoadExpr *>(),
1599
+ var->getDescriptiveKind (), var->getName ());
1600
+ return true ;
1601
+ }
1602
+
1603
+ if (auto func = dyn_cast<FuncDecl>(value)) {
1604
+ if (func->isConcurrent ())
1605
+ return false ;
1606
+
1607
+ func->diagnose (
1608
+ diag::local_function_executed_concurrently,
1609
+ func->getDescriptiveKind (), func->getName ())
1610
+ .fixItInsert (func->getAttributeInsertionLoc (false ), " @concurrent " );
1611
+
1612
+ // Add the @concurrent attribute implicitly, so we don't diagnose
1613
+ // again.
1614
+ const_cast <FuncDecl *>(func)->getAttrs ().add (
1615
+ new (ctx) ConcurrentAttr (true ));
1616
+ return true ;
1617
+ }
1618
+
1619
+ // Concurrent access to some other local.
1620
+ ctx.Diags .diagnose (
1621
+ loc, diag::concurrent_access_local,
1622
+ value->getDescriptiveKind (), value->getName ());
1623
+ value->diagnose (
1624
+ diag::kind_declared_here, value->getDescriptiveKind ());
1625
+ return true ;
1626
+ }
1627
+
1529
1628
// / Check a reference to a local or global.
1530
1629
bool checkNonMemberReference (
1531
1630
ConcreteDeclRef valueRef, SourceLoc loc, DeclRefExpr *declRefExpr) {
1532
1631
if (!valueRef)
1533
1632
return false ;
1534
1633
1535
1634
auto value = valueRef.getDecl ();
1635
+
1636
+ if (value->isLocalCapture ())
1637
+ return checkLocalCapture (valueRef, loc, declRefExpr);
1638
+
1536
1639
switch (auto isolation =
1537
1640
ActorIsolationRestriction::forDeclaration (valueRef)) {
1538
1641
case ActorIsolationRestriction::Unrestricted:
@@ -1548,64 +1651,6 @@ namespace {
1548
1651
valueRef, loc, isolation.getGlobalActor (),
1549
1652
isolation == ActorIsolationRestriction::CrossGlobalActor);
1550
1653
1551
- case ActorIsolationRestriction::LocalCapture:
1552
- // Check whether we are in a context that will not execute concurrently
1553
- // with the context of 'self'. If not, it's safe.
1554
- if (!mayExecuteConcurrentlyWith (
1555
- getDeclContext (), isolation.getLocalContext ()))
1556
- return false ;
1557
-
1558
- // Check whether this is a local variable, in which case we can
1559
- // determine whether it was safe to access concurrently.
1560
- if (auto var = dyn_cast<VarDecl>(value)) {
1561
- auto parent = mutableLocalVarParent[declRefExpr];
1562
-
1563
- // If the variable is immutable, it's fine so long as it involves
1564
- // ConcurrentValue types.
1565
- //
1566
- // When flow-sensitive concurrent captures are enabled, we also
1567
- // allow reads, depending on a SIL diagnostic pass to identify the
1568
- // remaining race conditions.
1569
- if (!var->supportsMutation () ||
1570
- (ctx.LangOpts .EnableExperimentalFlowSensitiveConcurrentCaptures &&
1571
- parent.dyn_cast <LoadExpr *>())) {
1572
- return diagnoseNonConcurrentTypesInReference (
1573
- valueRef, getDeclContext (), loc,
1574
- ConcurrentReferenceKind::LocalCapture);
1575
- }
1576
-
1577
- // Otherwise, we have concurrent access. Complain.
1578
- ctx.Diags .diagnose (
1579
- loc, diag::concurrent_access_of_local_capture,
1580
- parent.dyn_cast <LoadExpr *>(),
1581
- var->getDescriptiveKind (), var->getName ());
1582
- return true ;
1583
- }
1584
-
1585
- if (auto func = dyn_cast<FuncDecl>(value)) {
1586
- if (func->isConcurrent ())
1587
- return false ;
1588
-
1589
- func->diagnose (
1590
- diag::local_function_executed_concurrently,
1591
- func->getDescriptiveKind (), func->getName ())
1592
- .fixItInsert (func->getAttributeInsertionLoc (false ), " @concurrent " );
1593
-
1594
- // Add the @concurrent attribute implicitly, so we don't diagnose
1595
- // again.
1596
- const_cast <FuncDecl *>(func)->getAttrs ().add (
1597
- new (ctx) ConcurrentAttr (true ));
1598
- return true ;
1599
- }
1600
-
1601
- // Concurrent access to some other local.
1602
- ctx.Diags .diagnose (
1603
- loc, diag::concurrent_access_local,
1604
- value->getDescriptiveKind (), value->getName ());
1605
- value->diagnose (
1606
- diag::kind_declared_here, value->getDescriptiveKind ());
1607
- return true ;
1608
-
1609
1654
case ActorIsolationRestriction::Unsafe:
1610
1655
return diagnoseReferenceToUnsafeGlobal (value, loc);
1611
1656
}
@@ -1756,9 +1801,6 @@ namespace {
1756
1801
memberRef, memberLoc, isolation.getGlobalActor (),
1757
1802
isolation == ActorIsolationRestriction::CrossGlobalActor);
1758
1803
1759
- case ActorIsolationRestriction::LocalCapture:
1760
- llvm_unreachable (" Locals cannot be referenced with member syntax" );
1761
-
1762
1804
case ActorIsolationRestriction::Unsafe:
1763
1805
// This case is hit when passing actor state inout to functions in some
1764
1806
// cases. The error is emitted by diagnoseInOutArg.
0 commit comments