Skip to content

Commit ce90767

Browse files
authored
Merge pull request #34260 from kavon/actorUnsafe
[concurrency] implement the 'unsafe' option for @actorIndependent
2 parents 9671299 + 0752121 commit ce90767

20 files changed

+464
-51
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ class ActorIsolation {
4848
/// meaning that it can be used from any actor but is also unable to
4949
/// refer to the isolated state of any given actor.
5050
Independent,
51+
/// The declaration is explicitly specified to be independent of any actor,
52+
/// but the programmer promises to protect the declaration from concurrent
53+
/// accesses manually. Thus, it is okay if this declaration is a mutable
54+
/// variable that creates storage.
55+
IndependentUnsafe,
5156
/// The declaration is isolated to a global actor. It can refer to other
5257
/// entities with the same global actor.
5358
GlobalActor,
@@ -70,8 +75,18 @@ class ActorIsolation {
7075
return ActorIsolation(Unspecified, nullptr);
7176
}
7277

73-
static ActorIsolation forIndependent() {
74-
return ActorIsolation(Independent, nullptr);
78+
static ActorIsolation forIndependent(ActorIndependentKind indepKind) {
79+
ActorIsolation::Kind isoKind;
80+
switch (indepKind) {
81+
case ActorIndependentKind::Safe:
82+
isoKind = Independent;
83+
break;
84+
85+
case ActorIndependentKind::Unsafe:
86+
isoKind = IndependentUnsafe;
87+
break;
88+
}
89+
return ActorIsolation(isoKind, nullptr);
7590
}
7691

7792
static ActorIsolation forActorInstance(ClassDecl *actor) {
@@ -112,6 +127,7 @@ class ActorIsolation {
112127

113128
switch (lhs.kind) {
114129
case Independent:
130+
case IndependentUnsafe:
115131
case Unspecified:
116132
return true;
117133

include/swift/AST/Attr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(actor, Actor,
571571
APIBreakingToAdd | APIBreakingToRemove,
572572
102)
573573

574-
SIMPLE_DECL_ATTR(actorIndependent, ActorIndependent,
574+
DECL_ATTR(actorIndependent, ActorIndependent,
575575
OnFunc | OnVar | OnSubscript | ConcurrencyOnly |
576576
ABIStableToAdd | ABIStableToRemove |
577577
APIStableToAdd | APIBreakingToRemove,

include/swift/AST/Attr.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,10 @@ class DeclAttribute : public AttributeBase {
290290
kind : NumInlineKindBits
291291
);
292292

293+
SWIFT_INLINE_BITFIELD(ActorIndependentAttr, DeclAttribute, NumActorIndependentKindBits,
294+
kind : NumActorIndependentKindBits
295+
);
296+
293297
SWIFT_INLINE_BITFIELD(OptimizeAttr, DeclAttribute, NumOptimizationModeBits,
294298
mode : NumOptimizationModeBits
295299
);
@@ -1329,6 +1333,25 @@ class ReferenceOwnershipAttr : public DeclAttribute {
13291333
}
13301334
};
13311335

1336+
/// Represents an actorIndependent/actorIndependent(unsafe) decl attribute.
1337+
class ActorIndependentAttr : public DeclAttribute {
1338+
public:
1339+
ActorIndependentAttr(SourceLoc atLoc, SourceRange range, ActorIndependentKind kind)
1340+
: DeclAttribute(DAK_ActorIndependent, atLoc, range, /*Implicit=*/false) {
1341+
Bits.ActorIndependentAttr.kind = unsigned(kind);
1342+
}
1343+
1344+
ActorIndependentAttr(ActorIndependentKind kind, bool IsImplicit=false)
1345+
: ActorIndependentAttr(SourceLoc(), SourceRange(), kind) {
1346+
setImplicit(IsImplicit);
1347+
}
1348+
1349+
ActorIndependentKind getKind() const { return ActorIndependentKind(Bits.ActorIndependentAttr.kind); }
1350+
static bool classof(const DeclAttribute *DA) {
1351+
return DA->getKind() == DAK_ActorIndependent;
1352+
}
1353+
};
1354+
13321355
/// Defines the attribute that we use to model documentation comments.
13331356
class RawDocCommentAttr : public DeclAttribute {
13341357
/// Source range of the attached comment. This comment is located before

include/swift/AST/AttrKind.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,17 @@ enum class InlineKind : uint8_t {
7979
enum : unsigned { NumInlineKindBits =
8080
countBitsUsed(static_cast<unsigned>(InlineKind::Last_InlineKind)) };
8181

82+
83+
/// Indicates whether an actorIndependent decl is unsafe or not
84+
enum class ActorIndependentKind : uint8_t {
85+
Safe = 0,
86+
Unsafe = 1,
87+
Last_InlineKind = Unsafe
88+
};
89+
90+
enum : unsigned { NumActorIndependentKindBits =
91+
countBitsUsed(static_cast<unsigned>(ActorIndependentKind::Last_InlineKind)) };
92+
8293
/// This enum represents the possible values of the @_effects attribute.
8394
/// These values are ordered from the strongest guarantee to the weakest,
8495
/// so please do not reorder existing values.

include/swift/AST/DiagnosticsParse.def

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,12 @@ ERROR(attr_expected_comma,none,
13581358
ERROR(attr_expected_string_literal,none,
13591359
"expected string literal in '%0' attribute", (StringRef))
13601360

1361+
ERROR(attr_expected_option_such_as,none,
1362+
"expected '%0' option such as '%1'", (StringRef, StringRef))
1363+
1364+
ERROR(attr_unknown_option,none,
1365+
"unknown option '%0' for attribute '%1'", (StringRef, StringRef))
1366+
13611367
ERROR(attr_missing_label,PointsToFirstBadToken,
13621368
"missing label '%0:' in '@%1' attribute", (StringRef, StringRef))
13631369
ERROR(attr_expected_label,none,
@@ -1533,17 +1539,9 @@ ERROR(opened_attribute_id_value,none,
15331539
ERROR(opened_attribute_expected_rparen,none,
15341540
"expected ')' after id value for 'opened' attribute", ())
15351541

1536-
// inline, optimize
1537-
ERROR(optimization_attribute_expect_option,none,
1538-
"expected '%0' option such as '%1'", (StringRef, StringRef))
1539-
ERROR(optimization_attribute_unknown_option,none,
1540-
"unknown option '%0' for attribute '%1'", (StringRef, StringRef))
1541-
15421542
// effects
15431543
ERROR(effects_attribute_expect_option,none,
15441544
"expected '%0' option (readnone, readonly, readwrite)", (StringRef))
1545-
ERROR(effects_attribute_unknown_option,none,
1546-
"unknown option '%0' for attribute '%1'", (StringRef, StringRef))
15471545

15481546
// unowned
15491547
ERROR(attr_unowned_invalid_specifier,none,

include/swift/AST/DiagnosticsSema.def

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4207,22 +4207,22 @@ ERROR(global_actor_isolated_requirement_witness_conflict,none,
42074207
"requirement from protocol %3 isolated to global actor %4",
42084208
(DescriptiveDeclKind, DeclName, Type, Identifier, Type))
42094209

4210-
ERROR(actorisolated_let,none,
4211-
"'@actorIsolated' is meaningless on 'let' declarations because "
4210+
ERROR(actorindependent_let,none,
4211+
"'@actorIndependent' is meaningless on 'let' declarations because "
42124212
"they are immutable",
42134213
())
4214-
ERROR(actorisolated_mutable_storage,none,
4215-
"'@actorIsolated' can not be applied to stored properties",
4214+
ERROR(actorindependent_mutable_storage,none,
4215+
"'@actorIndependent' can not be applied to stored properties",
42164216
())
4217-
ERROR(actorisolated_local_var,none,
4218-
"'@actorIsolated' can not be applied to local variables",
4217+
ERROR(actorindependent_local_var,none,
4218+
"'@actorIndependent' can not be applied to local variables",
42194219
())
4220-
ERROR(actorisolated_not_actor_member,none,
4221-
"'@actorIsolated' can only be applied to actor members and "
4220+
ERROR(actorindependent_not_actor_member,none,
4221+
"'@actorIndependent' can only be applied to actor members and "
42224222
"global/static variables",
42234223
())
4224-
ERROR(actorisolated_not_actor_instance_member,none,
4225-
"'@actorIsolated' can only be applied to instance members of actors",
4224+
ERROR(actorindependent_not_actor_instance_member,none,
4225+
"'@actorIndependent' can only be applied to instance members of actors",
42264226
())
42274227

42284228
ERROR(concurrency_lib_missing,none,

lib/AST/Attr.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
769769
case DAK_ReferenceOwnership:
770770
case DAK_Effects:
771771
case DAK_Optimize:
772+
case DAK_ActorIndependent:
772773
if (DeclAttribute::isDeclModifier(getKind())) {
773774
Printer.printKeyword(getAttrName(), Options);
774775
} else {
@@ -1136,6 +1137,15 @@ StringRef DeclAttribute::getAttrName() const {
11361137
}
11371138
llvm_unreachable("Invalid inline kind");
11381139
}
1140+
case DAK_ActorIndependent: {
1141+
switch (cast<ActorIndependentAttr>(this)->getKind()) {
1142+
case ActorIndependentKind::Safe:
1143+
return "actorIndependent";
1144+
case ActorIndependentKind::Unsafe:
1145+
return "actorIndependent(unsafe)";
1146+
}
1147+
llvm_unreachable("Invalid actorIndependent kind");
1148+
}
11391149
case DAK_Optimize: {
11401150
switch (cast<OptimizeAttr>(this)->getMode()) {
11411151
case OptimizationMode::NoOptimization:

lib/AST/DiagnosticEngine.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,10 @@ static void formatDiagnosticArgument(StringRef Modifier,
676676
Out << "actor-independent";
677677
break;
678678

679+
case ActorIsolation::IndependentUnsafe:
680+
Out << "actor-independent-unsafe";
681+
break;
682+
679683
case ActorIsolation::Unspecified:
680684
Out << "non-actor-isolated";
681685
break;

lib/AST/TypeCheckRequests.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,6 +1495,7 @@ bool ActorIsolation::requiresSubstitution() const {
14951495
switch (kind) {
14961496
case ActorInstance:
14971497
case Independent:
1498+
case IndependentUnsafe:
14981499
case Unspecified:
14991500
return false;
15001501

@@ -1508,6 +1509,7 @@ ActorIsolation ActorIsolation::subst(SubstitutionMap subs) const {
15081509
switch (kind) {
15091510
case ActorInstance:
15101511
case Independent:
1512+
case IndependentUnsafe:
15111513
case Unspecified:
15121514
return *this;
15131515

@@ -1528,6 +1530,10 @@ void swift::simple_display(
15281530
out << "actor-independent";
15291531
break;
15301532

1533+
case ActorIsolation::IndependentUnsafe:
1534+
out << "actor-independent (unsafe)";
1535+
break;
1536+
15311537
case ActorIsolation::Unspecified:
15321538
out << "unspecified actor isolation";
15331539
break;

lib/Parse/ParseDecl.cpp

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,7 +1618,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
16181618
else if (Tok.getText() == "releasenone")
16191619
kind = EffectsKind::ReleaseNone;
16201620
else {
1621-
diagnose(Loc, diag::effects_attribute_unknown_option,
1621+
diagnose(Loc, diag::attr_unknown_option,
16221622
Tok.getText(), AttrName);
16231623
return false;
16241624
}
@@ -1644,8 +1644,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
16441644
}
16451645

16461646
if (Tok.isNot(tok::identifier)) {
1647-
diagnose(Loc, diag::optimization_attribute_expect_option, AttrName,
1648-
"none");
1647+
diagnose(Loc, diag::attr_expected_option_such_as, AttrName, "none");
16491648
return false;
16501649
}
16511650

@@ -1655,8 +1654,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
16551654
else if (Tok.getText() == "__always")
16561655
kind = InlineKind::Always;
16571656
else {
1658-
diagnose(Loc, diag::optimization_attribute_unknown_option,
1659-
Tok.getText(), AttrName);
1657+
diagnose(Loc, diag::attr_unknown_option, Tok.getText(), AttrName);
16601658
return false;
16611659
}
16621660
consumeToken(tok::identifier);
@@ -1674,6 +1672,45 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
16741672
break;
16751673
}
16761674

1675+
case DAK_ActorIndependent: {
1676+
// if no option is provided, then it's the 'safe' version.
1677+
if (!consumeIf(tok::l_paren)) {
1678+
if (!DiscardAttribute) {
1679+
AttrRange = SourceRange(Loc, Tok.getRange().getStart());
1680+
Attributes.add(new (Context) ActorIndependentAttr(AtLoc, AttrRange,
1681+
ActorIndependentKind::Safe));
1682+
}
1683+
break;
1684+
}
1685+
1686+
// otherwise, make sure it looks like an identifier.
1687+
if (Tok.isNot(tok::identifier)) {
1688+
diagnose(Loc, diag::attr_expected_option_such_as, AttrName, "unsafe");
1689+
return false;
1690+
}
1691+
1692+
// make sure the identifier is 'unsafe'
1693+
if (Tok.getText() != "unsafe") {
1694+
diagnose(Loc, diag::attr_unknown_option, Tok.getText(), AttrName);
1695+
return false;
1696+
}
1697+
1698+
consumeToken(tok::identifier);
1699+
AttrRange = SourceRange(Loc, Tok.getRange().getStart());
1700+
1701+
if (!consumeIf(tok::r_paren)) {
1702+
diagnose(Loc, diag::attr_expected_rparen, AttrName,
1703+
DeclAttribute::isDeclModifier(DK));
1704+
return false;
1705+
}
1706+
1707+
if (!DiscardAttribute)
1708+
Attributes.add(new (Context) ActorIndependentAttr(AtLoc, AttrRange,
1709+
ActorIndependentKind::Unsafe));
1710+
1711+
break;
1712+
}
1713+
16771714
case DAK_Optimize: {
16781715
if (!consumeIf(tok::l_paren)) {
16791716
diagnose(Loc, diag::attr_expected_lparen, AttrName,
@@ -1682,8 +1719,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
16821719
}
16831720

16841721
if (Tok.isNot(tok::identifier)) {
1685-
diagnose(Loc, diag::optimization_attribute_expect_option, AttrName,
1686-
"speed");
1722+
diagnose(Loc, diag::attr_expected_option_such_as, AttrName, "speed");
16871723
return false;
16881724
}
16891725

@@ -1695,8 +1731,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
16951731
else if (Tok.getText() == "size")
16961732
optMode = OptimizationMode::ForSize;
16971733
else {
1698-
diagnose(Loc, diag::optimization_attribute_unknown_option,
1699-
Tok.getText(), AttrName);
1734+
diagnose(Loc, diag::attr_unknown_option, Tok.getText(), AttrName);
17001735
return false;
17011736
}
17021737
consumeToken(tok::identifier);

lib/Sema/DerivedConformanceActor.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,9 @@ static ValueDecl *deriveActor_enqueuePartialTask(DerivedConformance &derived) {
236236
func->copyFormalAccessFrom(derived.Nominal);
237237
func->setBodySynthesizer(deriveBodyActor_enqueuePartialTask);
238238
func->setSynthesized();
239-
240-
// FIXME: This function should be "actor-unsafe", not "actor-independent", but
241-
// the latter is all we have at the moment.
242-
func->getAttrs().add(new (ctx) ActorIndependentAttr(/*IsImplicit=*/true));
239+
// mark as @actorIndependent(unsafe)
240+
func->getAttrs().add(new (ctx) ActorIndependentAttr(
241+
ActorIndependentKind::Unsafe, /*IsImplicit=*/true));
243242

244243
// Actor storage property and its initialization.
245244
auto actorStorage = new (ctx) VarDecl(

lib/Sema/TypeCheckAttr.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -286,19 +286,26 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
286286
if (auto var = dyn_cast<VarDecl>(D)) {
287287
// @actorIndependent is meaningless on a `let`.
288288
if (var->isLet()) {
289-
diagnoseAndRemoveAttr(attr, diag::actorisolated_let);
289+
diagnoseAndRemoveAttr(attr, diag::actorindependent_let);
290290
return;
291291
}
292292

293-
// @actorIndependent can not be applied to stored properties.
293+
// @actorIndependent can not be applied to stored properties, unless if
294+
// the 'unsafe' option was specified
294295
if (var->hasStorage()) {
295-
diagnoseAndRemoveAttr(attr, diag::actorisolated_mutable_storage);
296-
return;
296+
switch (attr->getKind()) {
297+
case ActorIndependentKind::Safe:
298+
diagnoseAndRemoveAttr(attr, diag::actorindependent_mutable_storage);
299+
return;
300+
301+
case ActorIndependentKind::Unsafe:
302+
break;
303+
}
297304
}
298305

299306
// @actorIndependent can not be applied to local properties.
300307
if (dc->isLocalContext()) {
301-
diagnoseAndRemoveAttr(attr, diag::actorisolated_local_var);
308+
diagnoseAndRemoveAttr(attr, diag::actorindependent_local_var);
302309
return;
303310
}
304311

@@ -315,14 +322,14 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
315322
// @actorIndependent only makes sense on an actor instance member.
316323
if (!dc->getSelfClassDecl() ||
317324
!dc->getSelfClassDecl()->isActor()) {
318-
diagnoseAndRemoveAttr(attr, diag::actorisolated_not_actor_member);
325+
diagnoseAndRemoveAttr(attr, diag::actorindependent_not_actor_member);
319326
return;
320327
}
321328

322329
auto VD = cast<ValueDecl>(D);
323330
if (!VD->isInstanceMember()) {
324331
diagnoseAndRemoveAttr(
325-
attr, diag::actorisolated_not_actor_instance_member);
332+
attr, diag::actorindependent_not_actor_instance_member);
326333
return;
327334
}
328335

0 commit comments

Comments
 (0)