Skip to content

Commit 82e111a

Browse files
authored
Merge pull request #78704 from xedin/rdar-142920095
Implement experimental`@execution(concurrent | caller)` attribute
2 parents cc9713b + fc1e650 commit 82e111a

21 files changed

+438
-10
lines changed

include/swift/AST/ASTBridging.h

+10
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,16 @@ BridgedABIAttr BridgedABIAttr_createParsed(
601601
BridgedASTContext cContext, BridgedSourceLoc atLoc,
602602
BridgedSourceRange range, BridgedNullableDecl abiDecl);
603603

604+
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedExecutionKind {
605+
BridgedExecutionKindConcurrent,
606+
BridgedExecutionKindCaller,
607+
};
608+
609+
SWIFT_NAME("BridgedExecutionAttr.createParsed(_:atLoc:range:behavior:)")
610+
BridgedExecutionAttr BridgedExecutionAttr_createParsed(
611+
BridgedASTContext cContext, BridgedSourceLoc atLoc,
612+
BridgedSourceRange range, BridgedExecutionKind behavior);
613+
604614
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedAccessLevel {
605615
BridgedAccessLevelPrivate,
606616
BridgedAccessLevelFilePrivate,

include/swift/AST/Attr.h

+28
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ class DeclAttribute : public AttributeBase {
217217

218218
NumFeatures : 31
219219
);
220+
221+
SWIFT_INLINE_BITFIELD(ExecutionAttr, DeclAttribute, NumExecutionKindBits,
222+
Behavior : NumExecutionKindBits
223+
);
220224
} Bits;
221225
// clang-format on
222226

@@ -2916,6 +2920,30 @@ class ABIAttr : public DeclAttribute {
29162920
UNIMPLEMENTED_CLONE(ABIAttr)
29172921
};
29182922

2923+
class ExecutionAttr : public DeclAttribute {
2924+
public:
2925+
ExecutionAttr(SourceLoc AtLoc, SourceRange Range,
2926+
ExecutionKind behavior,
2927+
bool Implicit)
2928+
: DeclAttribute(DeclAttrKind::Execution, AtLoc, Range, Implicit) {
2929+
Bits.ExecutionAttr.Behavior = static_cast<uint8_t>(behavior);
2930+
}
2931+
2932+
ExecutionAttr(ExecutionKind behavior, bool Implicit)
2933+
: ExecutionAttr(/*AtLoc=*/SourceLoc(), /*Range=*/SourceRange(), behavior,
2934+
Implicit) {}
2935+
2936+
ExecutionKind getBehavior() const {
2937+
return static_cast<ExecutionKind>(Bits.ExecutionAttr.Behavior);
2938+
}
2939+
2940+
static bool classof(const DeclAttribute *DA) {
2941+
return DA->getKind() == DeclAttrKind::Execution;
2942+
}
2943+
2944+
UNIMPLEMENTED_CLONE(ExecutionAttr)
2945+
};
2946+
29192947
/// Attributes that may be applied to declarations.
29202948
class DeclAttributes {
29212949
/// Linked list of declaration attributes.

include/swift/AST/AttrKind.h

+9
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ enum class ExternKind: uint8_t {
130130
enum : unsigned { NumExternKindBits =
131131
countBitsUsed(static_cast<unsigned>(ExternKind::Last_ExternKind)) };
132132

133+
enum class ExecutionKind : uint8_t {
134+
Concurrent = 0,
135+
Caller,
136+
Last_ExecutionKind = Caller
137+
};
138+
139+
enum : unsigned { NumExecutionKindBits =
140+
countBitsUsed(static_cast<unsigned>(ExecutionKind::Last_ExecutionKind)) };
141+
133142
enum class DeclAttrKind : unsigned {
134143
#define DECL_ATTR(_, CLASS, ...) CLASS,
135144
#define LAST_DECL_ATTR(CLASS) Last_DeclAttr = CLASS,

include/swift/AST/DeclAttr.def

+6-1
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,12 @@ DECL_ATTR(abi, ABI,
538538
165)
539539
DECL_ATTR_FEATURE_REQUIREMENT(ABI, ABIAttribute)
540540

541-
LAST_DECL_ATTR(ABI)
541+
DECL_ATTR(execution, Execution,
542+
OnFunc | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
543+
166)
544+
DECL_ATTR_FEATURE_REQUIREMENT(Execution, NonIsolatedAsyncInheritsIsolationFromContext)
545+
546+
LAST_DECL_ATTR(Execution)
542547

543548
#undef DECL_ATTR_ALIAS
544549
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/DiagnosticsSema.def

+27
Original file line numberDiff line numberDiff line change
@@ -8211,5 +8211,32 @@ ERROR(attr_abi_incompatible_with_silgen_name,none,
82118211
"the same purpose",
82128212
(DescriptiveDeclKind))
82138213

8214+
//===----------------------------------------------------------------------===//
8215+
// MARK: @execution Attribute
8216+
//===----------------------------------------------------------------------===//
8217+
ERROR(attr_execution_concurrent_only_on_async,none,
8218+
"cannot use '@execution(concurrent)' on non-async %kind0",
8219+
(ValueDecl *))
8220+
8221+
ERROR(attr_execution_concurrent_incompatible_with_global_actor,none,
8222+
"cannot use '@execution(concurrent)' on %kind0 isolated to global actor %1",
8223+
(ValueDecl *, Type))
8224+
8225+
ERROR(attr_execution_concurrent_incompatible_isolated_parameter,none,
8226+
"cannot use '@execution(concurrent)' on %kind0 because it has "
8227+
"an isolated parameter: %1",
8228+
(ValueDecl *, ValueDecl *))
8229+
8230+
ERROR(attr_execution_concurrent_incompatible_dynamically_isolated_parameter,none,
8231+
"cannot use '@execution(concurrent)' on %kind0 because it has "
8232+
"a dynamically isolated parameter: %1",
8233+
(ValueDecl *, ValueDecl *))
8234+
8235+
ERROR(attr_execution_concurrent_incompatible_with_nonisolated,none,
8236+
"cannot use '@execution(concurrent)' and 'nonisolated' on the same %0 "
8237+
"because they serve the same purpose",
8238+
(ValueDecl *))
8239+
8240+
82148241
#define UNDEFINE_DIAGNOSTIC_MACROS
82158242
#include "DefineDiagnosticMacros.h"

include/swift/AST/KnownIdentifiers.def

+2
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ IDENTIFIER(size)
332332
IDENTIFIER(speed)
333333
IDENTIFIER(unchecked)
334334
IDENTIFIER(unsafe)
335+
IDENTIFIER(concurrent)
336+
IDENTIFIER(caller)
335337

336338
// The singleton instance of TupleTypeDecl in the Builtin module
337339
IDENTIFIER(TheTupleType)

lib/AST/ASTDumper.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,14 @@ static StringRef getDumpString(NonSendableKind kind) {
526526
return "Specific";
527527
}
528528
}
529+
static StringRef getDumpString(ExecutionKind kind) {
530+
switch (kind) {
531+
case ExecutionKind::Concurrent:
532+
return "concurrent";
533+
case ExecutionKind::Caller:
534+
return "caller";
535+
}
536+
}
529537
static StringRef getDumpString(StringRef s) {
530538
return s;
531539
}
@@ -3871,6 +3879,11 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, StringRef>,
38713879

38723880
#undef TRIVIAL_ATTR_PRINTER
38733881

3882+
void visitExecutionAttr(ExecutionAttr *Attr, StringRef label) {
3883+
printCommon(Attr, "execution_attr", label);
3884+
printField(Attr->getBehavior(), "behavior");
3885+
printFoot();
3886+
}
38743887
void visitABIAttr(ABIAttr *Attr, StringRef label) {
38753888
printCommon(Attr, "abi_attr", label);
38763889
printRec(Attr->abiDecl, "decl");

lib/AST/Attr.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -1650,6 +1650,19 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
16501650
break;
16511651
}
16521652

1653+
case DeclAttrKind::Execution: {
1654+
auto *attr = cast<ExecutionAttr>(this);
1655+
switch (attr->getBehavior()) {
1656+
case ExecutionKind::Concurrent:
1657+
Printer << "@execution(concurrent)";
1658+
break;
1659+
case ExecutionKind::Caller:
1660+
Printer << "@execution(caller)";
1661+
break;
1662+
}
1663+
break;
1664+
}
1665+
16531666
#define SIMPLE_DECL_ATTR(X, CLASS, ...) case DeclAttrKind::CLASS:
16541667
#include "swift/AST/DeclAttr.def"
16551668
llvm_unreachable("handled above");
@@ -1861,6 +1874,15 @@ StringRef DeclAttribute::getAttrName() const {
18611874
}
18621875
case DeclAttrKind::Lifetime:
18631876
return "lifetime";
1877+
case DeclAttrKind::Execution: {
1878+
switch (cast<ExecutionAttr>(this)->getBehavior()) {
1879+
case ExecutionKind::Concurrent:
1880+
return "execution(concurrent)";
1881+
case ExecutionKind::Caller:
1882+
return "execution(caller)";
1883+
}
1884+
llvm_unreachable("Invalid execution kind");
1885+
}
18641886
}
18651887
llvm_unreachable("bad DeclAttrKind");
18661888
}

lib/AST/Bridging/DeclAttributeBridging.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -585,3 +585,21 @@ BridgedUnavailableFromAsyncAttr BridgedUnavailableFromAsyncAttr_createParsed(
585585
UnavailableFromAsyncAttr(cMessage.unbridged(), cAtLoc.unbridged(),
586586
cRange.unbridged(), /*implicit=*/false);
587587
}
588+
589+
static ExecutionKind unbridged(BridgedExecutionKind kind) {
590+
switch (kind) {
591+
case BridgedExecutionKindConcurrent:
592+
return ExecutionKind::Concurrent;
593+
case BridgedExecutionKindCaller:
594+
return ExecutionKind::Caller;
595+
}
596+
llvm_unreachable("unhandled enum value");
597+
}
598+
599+
BridgedExecutionAttr BridgedExecutionAttr_createParsed(
600+
BridgedASTContext cContext, BridgedSourceLoc atLoc,
601+
BridgedSourceRange range, BridgedExecutionKind behavior) {
602+
return new (cContext.unbridged())
603+
ExecutionAttr(atLoc.unbridged(), range.unbridged(),
604+
unbridged(behavior), /*implicit=*/false);
605+
}

lib/ASTGen/Sources/ASTGen/DeclAttrs.swift

+29
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ extension ASTGenVisitor {
111111
let attrName = identTy.name.rawText
112112
let attrKind = BridgedDeclAttrKind(from: attrName.bridged)
113113
switch attrKind {
114+
case .execution:
115+
return handle(self.generateExecutionAttr(attribute: node)?.asDeclAttribute)
114116
case .ABI:
115117
return handle(self.generateABIAttr(attribute: node)?.asDeclAttribute)
116118
case .alignment:
@@ -329,6 +331,33 @@ extension ASTGenVisitor {
329331
return handle(self.generateCustomAttr(attribute: node)?.asDeclAttribute)
330332
}
331333

334+
/// E.g.:
335+
/// ```
336+
/// @execution(concurrent)
337+
/// @execution(caller)
338+
/// ```
339+
func generateExecutionAttr(attribute node: AttributeSyntax) -> BridgedExecutionAttr? {
340+
let behavior: BridgedExecutionKind? = self.generateSingleAttrOption(
341+
attribute: node,
342+
{
343+
switch $0.rawText {
344+
case "concurrent": return .concurrent
345+
case "caller": return .caller
346+
default: return nil
347+
}
348+
}
349+
)
350+
guard let behavior else {
351+
return nil
352+
}
353+
return .createParsed(
354+
self.ctx,
355+
atLoc: self.generateSourceLoc(node.atSign),
356+
range: self.generateAttrSourceRange(node),
357+
behavior: behavior
358+
)
359+
}
360+
332361
/// E.g.:
333362
/// ```
334363
/// @abi(func fn())

lib/Parse/ParseDecl.cpp

+18-1
Original file line numberDiff line numberDiff line change
@@ -2706,6 +2706,8 @@ ParserResult<LifetimeAttr> Parser::parseLifetimeAttribute(SourceLoc atLoc,
27062706
/* implicit */ false, lifetimeEntry.get()));
27072707
}
27082708

2709+
2710+
27092711
/// Parses a (possibly optional) argument for an attribute containing a single, arbitrary identifier.
27102712
///
27112713
/// \param P The parser object.
@@ -4022,6 +4024,21 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
40224024
Attributes.add(Attr.get());
40234025
break;
40244026
}
4027+
4028+
case DeclAttrKind::Execution: {
4029+
auto behavior = parseSingleAttrOption<ExecutionKind>(
4030+
*this, Loc, AttrRange, AttrName, DK,
4031+
{{Context.Id_concurrent, ExecutionKind::Concurrent},
4032+
{Context.Id_caller, ExecutionKind::Caller}});
4033+
if (!behavior)
4034+
return makeParserSuccess();
4035+
4036+
if (!DiscardAttribute)
4037+
Attributes.add(new (Context) ExecutionAttr(AtLoc, AttrRange, *behavior,
4038+
/*Implicit*/ false));
4039+
4040+
break;
4041+
}
40254042
}
40264043

40274044
if (DuplicateAttribute) {
@@ -9728,7 +9745,7 @@ Parser::parseDeclSubscript(SourceLoc StaticLoc,
97289745
}
97299746
}
97309747
}
9731-
9748+
97329749
ParserStatus Status;
97339750
SourceLoc SubscriptLoc = consumeToken(tok::kw_subscript);
97349751

lib/Sema/TypeCheckAttr.cpp

+75
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,81 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
253253
}
254254

255255
public:
256+
void visitExecutionAttr(ExecutionAttr *attr) {
257+
auto *F = dyn_cast<FuncDecl>(D);
258+
if (!F)
259+
return;
260+
261+
if (!F->hasAsync()) {
262+
diagnoseAndRemoveAttr(attr, diag::attr_execution_concurrent_only_on_async,
263+
F);
264+
return;
265+
}
266+
267+
switch (attr->getBehavior()) {
268+
case ExecutionKind::Concurrent: {
269+
// 'concurrent' doesn't work with explicit `nonisolated`
270+
if (F->hasExplicitIsolationAttribute()) {
271+
if (F->getAttrs().hasAttribute<NonisolatedAttr>()) {
272+
diagnoseAndRemoveAttr(
273+
attr,
274+
diag::attr_execution_concurrent_incompatible_with_nonisolated, F);
275+
return;
276+
}
277+
}
278+
279+
auto parameters = F->getParameters();
280+
if (!parameters)
281+
return;
282+
283+
for (auto *P : *parameters) {
284+
auto *repr = P->getTypeRepr();
285+
if (!repr)
286+
continue;
287+
288+
// isolated parameters affect isolation of the function itself
289+
if (isa<IsolatedTypeRepr>(repr)) {
290+
diagnoseAndRemoveAttr(
291+
attr,
292+
diag::attr_execution_concurrent_incompatible_isolated_parameter,
293+
F, P);
294+
return;
295+
}
296+
297+
if (auto *attrType = dyn_cast<AttributedTypeRepr>(repr)) {
298+
if (attrType->has(TypeAttrKind::Isolated)) {
299+
diagnoseAndRemoveAttr(
300+
attr,
301+
diag::
302+
attr_execution_concurrent_incompatible_dynamically_isolated_parameter,
303+
F, P);
304+
return;
305+
}
306+
}
307+
}
308+
309+
// We need isolation check here because global actor isolation
310+
// could be inferred.
311+
312+
auto isolation = getActorIsolation(F);
313+
if (isolation.isGlobalActor()) {
314+
diagnoseAndRemoveAttr(
315+
attr,
316+
diag::attr_execution_concurrent_incompatible_with_global_actor, F,
317+
isolation.getGlobalActor());
318+
return;
319+
}
320+
321+
break;
322+
}
323+
324+
case ExecutionKind::Caller: {
325+
// no restrictions for now.
326+
break;
327+
}
328+
}
329+
}
330+
256331
void visitABIAttr(ABIAttr *attr) {
257332
Decl *AD = attr->abiDecl;
258333
if (isa<VarDecl>(D) && isa<PatternBindingDecl>(AD)) {

lib/Sema/TypeCheckDeclOverride.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1593,6 +1593,7 @@ namespace {
15931593
UNINTERESTING_ATTR(DynamicCallable)
15941594
UNINTERESTING_ATTR(DynamicMemberLookup)
15951595
UNINTERESTING_ATTR(SILGenName)
1596+
UNINTERESTING_ATTR(Execution)
15961597
UNINTERESTING_ATTR(Exported)
15971598
UNINTERESTING_ATTR(ForbidSerializingReference)
15981599
UNINTERESTING_ATTR(GKInspectable)

0 commit comments

Comments
 (0)